about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--data/countryflags/AD.pngbin0 -> 2741 bytes
-rw-r--r--data/countryflags/AE.pngbin0 -> 816 bytes
-rw-r--r--data/countryflags/AF.pngbin0 -> 2631 bytes
-rw-r--r--data/countryflags/AG.pngbin0 -> 2161 bytes
-rw-r--r--data/countryflags/AI.pngbin0 -> 2544 bytes
-rw-r--r--data/countryflags/AL.pngbin0 -> 2347 bytes
-rw-r--r--data/countryflags/AM.pngbin0 -> 740 bytes
-rw-r--r--data/countryflags/AO.pngbin0 -> 1739 bytes
-rw-r--r--data/countryflags/AR.pngbin1571 -> 1519 bytes
-rw-r--r--data/countryflags/AS.pngbin0 -> 4005 bytes
-rw-r--r--data/countryflags/AT.pngbin1072 -> 798 bytes
-rw-r--r--data/countryflags/AU.pngbin3842 -> 2472 bytes
-rw-r--r--data/countryflags/AW.pngbin0 -> 1280 bytes
-rw-r--r--data/countryflags/AX.pngbin0 -> 985 bytes
-rw-r--r--data/countryflags/AZ.pngbin0 -> 1288 bytes
-rw-r--r--data/countryflags/BA.pngbin2868 -> 2175 bytes
-rw-r--r--data/countryflags/BB.pngbin0 -> 1354 bytes
-rw-r--r--data/countryflags/BD.pngbin0 -> 1145 bytes
-rw-r--r--data/countryflags/BE.pngbin879 -> 678 bytes
-rw-r--r--data/countryflags/BF.pngbin0 -> 1073 bytes
-rw-r--r--data/countryflags/BG.pngbin1006 -> 789 bytes
-rw-r--r--data/countryflags/BH.pngbin0 -> 1493 bytes
-rw-r--r--data/countryflags/BI.pngbin0 -> 2643 bytes
-rw-r--r--data/countryflags/BJ.pngbin0 -> 851 bytes
-rw-r--r--data/countryflags/BL.pngbin0 -> 6881 bytes
-rw-r--r--data/countryflags/BM.pngbin0 -> 3329 bytes
-rw-r--r--data/countryflags/BN.pngbin0 -> 3910 bytes
-rw-r--r--data/countryflags/BO.pngbin0 -> 1674 bytes
-rw-r--r--data/countryflags/BR.pngbin3905 -> 2682 bytes
-rw-r--r--data/countryflags/BS.pngbin0 -> 1216 bytes
-rw-r--r--data/countryflags/BT.pngbin0 -> 4193 bytes
-rw-r--r--data/countryflags/BW.pngbin0 -> 719 bytes
-rw-r--r--data/countryflags/BY.pngbin2728 -> 1869 bytes
-rw-r--r--data/countryflags/BZ.pngbin0 -> 5185 bytes
-rw-r--r--data/countryflags/CA.pngbin1885 -> 1436 bytes
-rw-r--r--data/countryflags/CC.pngbin0 -> 2056 bytes
-rw-r--r--data/countryflags/CD.pngbin0 -> 2868 bytes
-rw-r--r--data/countryflags/CF.pngbin0 -> 1148 bytes
-rw-r--r--data/countryflags/CG.pngbin0 -> 1580 bytes
-rw-r--r--data/countryflags/CH.pngbin1099 -> 896 bytes
-rw-r--r--data/countryflags/CI.pngbin0 -> 818 bytes
-rw-r--r--data/countryflags/CK.pngbin0 -> 3372 bytes
-rw-r--r--data/countryflags/CL.pngbin1422 -> 984 bytes
-rw-r--r--data/countryflags/CM.pngbin0 -> 1104 bytes
-rw-r--r--data/countryflags/CN.pngbin1720 -> 1331 bytes
-rw-r--r--data/countryflags/CO.pngbin993 -> 784 bytes
-rw-r--r--data/countryflags/CR.pngbin0 -> 1531 bytes
-rw-r--r--data/countryflags/CU.pngbin0 -> 1632 bytes
-rw-r--r--data/countryflags/CV.pngbin0 -> 1668 bytes
-rw-r--r--data/countryflags/CW.pngbin0 -> 1138 bytes
-rw-r--r--data/countryflags/CX.pngbin0 -> 2560 bytes
-rw-r--r--data/countryflags/CY.pngbin0 -> 1905 bytes
-rw-r--r--data/countryflags/CZ.pngbin1815 -> 962 bytes
-rw-r--r--data/countryflags/DE.pngbin863 -> 666 bytes
-rw-r--r--data/countryflags/DJ.pngbin0 -> 1758 bytes
-rw-r--r--data/countryflags/DK.pngbin1207 -> 863 bytes
-rw-r--r--data/countryflags/DM.pngbin0 -> 2237 bytes
-rw-r--r--data/countryflags/DO.pngbin0 -> 1646 bytes
-rw-r--r--data/countryflags/DZ.pngbin0 -> 1605 bytes
-rw-r--r--data/countryflags/EC.pngbin0 -> 2589 bytes
-rw-r--r--data/countryflags/EE.pngbin887 -> 632 bytes
-rw-r--r--data/countryflags/EG.pngbin1662 -> 1406 bytes
-rw-r--r--data/countryflags/EH.pngbin0 -> 1516 bytes
-rw-r--r--data/countryflags/ER.pngbin0 -> 3335 bytes
-rw-r--r--data/countryflags/ES.pngbin2406 -> 2174 bytes
-rw-r--r--data/countryflags/ET.pngbin0 -> 2587 bytes
-rw-r--r--data/countryflags/FI.pngbin1071 -> 832 bytes
-rw-r--r--data/countryflags/FJ.pngbin0 -> 3222 bytes
-rw-r--r--data/countryflags/FK.pngbin0 -> 4080 bytes
-rw-r--r--data/countryflags/FM.pngbin0 -> 1434 bytes
-rw-r--r--data/countryflags/FO.pngbin0 -> 994 bytes
-rw-r--r--data/countryflags/FR.pngbin1037 -> 814 bytes
-rw-r--r--data/countryflags/GA.pngbin0 -> 857 bytes
-rw-r--r--data/countryflags/GB.pngbin4786 -> 2870 bytes
-rw-r--r--data/countryflags/GD.pngbin0 -> 2669 bytes
-rw-r--r--data/countryflags/GE.pngbin0 -> 1595 bytes
-rw-r--r--data/countryflags/GF.pngbin0 -> 1637 bytes
-rw-r--r--data/countryflags/GG.pngbin0 -> 1143 bytes
-rw-r--r--data/countryflags/GH.pngbin0 -> 1152 bytes
-rw-r--r--data/countryflags/GI.pngbin0 -> 2466 bytes
-rw-r--r--data/countryflags/GL.pngbin0 -> 1130 bytes
-rw-r--r--data/countryflags/GM.pngbin0 -> 789 bytes
-rw-r--r--data/countryflags/GN.pngbin0 -> 822 bytes
-rw-r--r--data/countryflags/GP.pngbin0 -> 1180 bytes
-rw-r--r--data/countryflags/GQ.pngbin0 -> 1599 bytes
-rw-r--r--data/countryflags/GR.pngbin1439 -> 1011 bytes
-rw-r--r--data/countryflags/GS.pngbin0 -> 4830 bytes
-rw-r--r--data/countryflags/GT.pngbin0 -> 1910 bytes
-rw-r--r--data/countryflags/GU.pngbin0 -> 2242 bytes
-rw-r--r--data/countryflags/GW.pngbin0 -> 1138 bytes
-rw-r--r--data/countryflags/GY.pngbin0 -> 2993 bytes
-rw-r--r--data/countryflags/HK.pngbin0 -> 2097 bytes
-rw-r--r--data/countryflags/HN.pngbin0 -> 1224 bytes
-rw-r--r--data/countryflags/HR.pngbin2614 -> 2320 bytes
-rw-r--r--data/countryflags/HT.pngbin0 -> 1577 bytes
-rw-r--r--data/countryflags/HU.pngbin1027 -> 838 bytes
-rw-r--r--data/countryflags/ID.pngbin1017 -> 787 bytes
-rw-r--r--data/countryflags/IE.pngbin0 -> 847 bytes
-rw-r--r--data/countryflags/IL.pngbin2110 -> 1565 bytes
-rw-r--r--data/countryflags/IM.pngbin0 -> 2053 bytes
-rw-r--r--data/countryflags/IN.pngbin1841 -> 1518 bytes
-rw-r--r--data/countryflags/IO.pngbin0 -> 7189 bytes
-rw-r--r--data/countryflags/IQ.pngbin0 -> 1469 bytes
-rw-r--r--data/countryflags/IR.pngbin3227 -> 2604 bytes
-rw-r--r--data/countryflags/IS.pngbin0 -> 1017 bytes
-rw-r--r--data/countryflags/IT.pngbin1022 -> 861 bytes
-rw-r--r--data/countryflags/JE.pngbin0 -> 3269 bytes
-rw-r--r--data/countryflags/JM.pngbin0 -> 2407 bytes
-rw-r--r--data/countryflags/JO.pngbin0 -> 1048 bytes
-rw-r--r--data/countryflags/JP.pngbin0 -> 1397 bytes
-rw-r--r--data/countryflags/KE.pngbin0 -> 2149 bytes
-rw-r--r--data/countryflags/KG.pngbin0 -> 3085 bytes
-rw-r--r--data/countryflags/KH.pngbin0 -> 2424 bytes
-rw-r--r--data/countryflags/KI.pngbin0 -> 4268 bytes
-rw-r--r--data/countryflags/KM.pngbin0 -> 1804 bytes
-rw-r--r--data/countryflags/KN.pngbin0 -> 2524 bytes
-rw-r--r--data/countryflags/KP.pngbin0 -> 1618 bytes
-rw-r--r--data/countryflags/KR.pngbin0 -> 2860 bytes
-rw-r--r--data/countryflags/KW.pngbin0 -> 1119 bytes
-rw-r--r--data/countryflags/KY.pngbin0 -> 3989 bytes
-rw-r--r--data/countryflags/KZ.pngbin4339 -> 3021 bytes
-rw-r--r--data/countryflags/LA.pngbin0 -> 1033 bytes
-rw-r--r--data/countryflags/LB.pngbin0 -> 1918 bytes
-rw-r--r--data/countryflags/LC.pngbin0 -> 1904 bytes
-rw-r--r--data/countryflags/LI.pngbin0 -> 1598 bytes
-rw-r--r--data/countryflags/LK.pngbin0 -> 4089 bytes
-rw-r--r--data/countryflags/LR.pngbin0 -> 1268 bytes
-rw-r--r--data/countryflags/LS.pngbin0 -> 1378 bytes
-rw-r--r--data/countryflags/LT.pngbin991 -> 758 bytes
-rw-r--r--data/countryflags/LU.pngbin1089 -> 832 bytes
-rw-r--r--data/countryflags/LV.pngbin1052 -> 771 bytes
-rw-r--r--data/countryflags/LY.pngbin0 -> 634 bytes
-rw-r--r--data/countryflags/MA.pngbin0 -> 1667 bytes
-rw-r--r--data/countryflags/MC.pngbin0 -> 764 bytes
-rw-r--r--data/countryflags/MD.pngbin0 -> 2601 bytes
-rw-r--r--data/countryflags/ME.pngbin0 -> 3243 bytes
-rw-r--r--data/countryflags/MF.pngbin0 -> 1623 bytes
-rw-r--r--data/countryflags/MG.pngbin0 -> 894 bytes
-rw-r--r--data/countryflags/MH.pngbin0 -> 3355 bytes
-rw-r--r--data/countryflags/MK.pngbin0 -> 2768 bytes
-rw-r--r--data/countryflags/ML.pngbin0 -> 832 bytes
-rw-r--r--data/countryflags/MM.pngbin0 -> 1550 bytes
-rw-r--r--data/countryflags/MN.pngbin0 -> 1718 bytes
-rw-r--r--data/countryflags/MO.pngbin0 -> 2064 bytes
-rw-r--r--data/countryflags/MP.pngbin0 -> 5386 bytes
-rw-r--r--data/countryflags/MQ.pngbin0 -> 3036 bytes
-rw-r--r--data/countryflags/MR.pngbin0 -> 1559 bytes
-rw-r--r--data/countryflags/MS.pngbin0 -> 2919 bytes
-rw-r--r--data/countryflags/MT.pngbin0 -> 1263 bytes
-rw-r--r--data/countryflags/MU.pngbin0 -> 843 bytes
-rw-r--r--data/countryflags/MV.pngbin0 -> 1140 bytes
-rw-r--r--data/countryflags/MW.pngbin0 -> 2357 bytes
-rw-r--r--data/countryflags/MX.pngbin2486 -> 2211 bytes
-rw-r--r--data/countryflags/MY.pngbin0 -> 2080 bytes
-rw-r--r--data/countryflags/MZ.pngbin0 -> 2087 bytes
-rw-r--r--data/countryflags/NA.pngbin0 -> 3339 bytes
-rw-r--r--data/countryflags/NC.pngbin0 -> 2547 bytes
-rw-r--r--data/countryflags/NE.pngbin0 -> 1060 bytes
-rw-r--r--data/countryflags/NF.pngbin0 -> 2791 bytes
-rw-r--r--data/countryflags/NG.pngbin0 -> 771 bytes
-rw-r--r--data/countryflags/NI.pngbin0 -> 1463 bytes
-rw-r--r--data/countryflags/NL.pngbin1064 -> 825 bytes
-rw-r--r--data/countryflags/NO.pngbin1327 -> 975 bytes
-rw-r--r--data/countryflags/NP.pngbin0 -> 2085 bytes
-rw-r--r--data/countryflags/NR.pngbin0 -> 1294 bytes
-rw-r--r--data/countryflags/NU.pngbin0 -> 2806 bytes
-rw-r--r--data/countryflags/NZ.pngbin0 -> 2166 bytes
-rw-r--r--data/countryflags/OM.pngbin0 -> 1496 bytes
-rw-r--r--data/countryflags/PA.pngbin0 -> 1385 bytes
-rw-r--r--data/countryflags/PE.pngbin0 -> 794 bytes
-rw-r--r--data/countryflags/PF.pngbin0 -> 1967 bytes
-rw-r--r--data/countryflags/PG.pngbin0 -> 2315 bytes
-rw-r--r--data/countryflags/PH.pngbin2843 -> 2109 bytes
-rw-r--r--data/countryflags/PK.pngbin2180 -> 1638 bytes
-rw-r--r--data/countryflags/PL.pngbin988 -> 753 bytes
-rw-r--r--data/countryflags/PM.pngbin0 -> 7849 bytes
-rw-r--r--data/countryflags/PN.pngbin0 -> 4692 bytes
-rw-r--r--data/countryflags/PR.pngbin0 -> 1670 bytes
-rw-r--r--data/countryflags/PT.pngbin2940 -> 2653 bytes
-rw-r--r--data/countryflags/PW.pngbin0 -> 1375 bytes
-rw-r--r--data/countryflags/PY.pngbin0 -> 1584 bytes
-rw-r--r--data/countryflags/QA.pngbin0 -> 1193 bytes
-rw-r--r--data/countryflags/RE.pngbin0 -> 1816 bytes
-rw-r--r--data/countryflags/RO.pngbin1002 -> 805 bytes
-rw-r--r--data/countryflags/RS.pngbin3666 -> 3054 bytes
-rw-r--r--data/countryflags/RU.pngbin989 -> 719 bytes
-rw-r--r--data/countryflags/RW.pngbin0 -> 1557 bytes
-rw-r--r--data/countryflags/SA.pngbin3662 -> 2605 bytes
-rw-r--r--data/countryflags/SB.pngbin0 -> 2399 bytes
-rw-r--r--data/countryflags/SC.pngbin0 -> 2184 bytes
-rw-r--r--data/countryflags/SD.pngbin0 -> 1015 bytes
-rw-r--r--data/countryflags/SE.pngbin1098 -> 849 bytes
-rw-r--r--data/countryflags/SG.pngbin0 -> 1407 bytes
-rw-r--r--data/countryflags/SH.pngbin0 -> 3167 bytes
-rw-r--r--data/countryflags/SI.pngbin0 -> 1507 bytes
-rw-r--r--data/countryflags/SK.pngbin2280 -> 1836 bytes
-rw-r--r--data/countryflags/SL.pngbin0 -> 836 bytes
-rw-r--r--data/countryflags/SM.pngbin0 -> 2585 bytes
-rw-r--r--data/countryflags/SN.pngbin0 -> 1108 bytes
-rw-r--r--data/countryflags/SO.pngbin0 -> 1181 bytes
-rw-r--r--data/countryflags/SR.pngbin0 -> 1260 bytes
-rw-r--r--data/countryflags/SS.pngbin0 -> 1437 bytes
-rw-r--r--data/countryflags/ST.pngbin0 -> 1348 bytes
-rw-r--r--data/countryflags/SV.pngbin1893 -> 1717 bytes
-rw-r--r--data/countryflags/SX.pngbin0 -> 2708 bytes
-rw-r--r--data/countryflags/SY.pngbin0 -> 1171 bytes
-rw-r--r--data/countryflags/SZ.pngbin0 -> 2458 bytes
-rw-r--r--data/countryflags/TC.pngbin0 -> 2398 bytes
-rw-r--r--data/countryflags/TD.pngbin0 -> 805 bytes
-rw-r--r--data/countryflags/TF.pngbin0 -> 1729 bytes
-rw-r--r--data/countryflags/TG.pngbin0 -> 1208 bytes
-rw-r--r--data/countryflags/TH.pngbin0 -> 797 bytes
-rw-r--r--data/countryflags/TJ.pngbin0 -> 1597 bytes
-rw-r--r--data/countryflags/TK.pngbin0 -> 2242 bytes
-rw-r--r--data/countryflags/TL.pngbin0 -> 1379 bytes
-rw-r--r--data/countryflags/TM.pngbin0 -> 3311 bytes
-rw-r--r--data/countryflags/TN.pngbin0 -> 1733 bytes
-rw-r--r--data/countryflags/TO.pngbin0 -> 832 bytes
-rw-r--r--data/countryflags/TR.pngbin2117 -> 1622 bytes
-rw-r--r--data/countryflags/TT.pngbin0 -> 1938 bytes
-rw-r--r--data/countryflags/TV.pngbin0 -> 3266 bytes
-rw-r--r--data/countryflags/TW.pngbin0 -> 1126 bytes
-rw-r--r--data/countryflags/TZ.pngbin0 -> 2300 bytes
-rw-r--r--data/countryflags/UA.pngbin938 -> 777 bytes
-rw-r--r--data/countryflags/UG.pngbin0 -> 1360 bytes
-rw-r--r--data/countryflags/US.pngbin3280 -> 2401 bytes
-rw-r--r--data/countryflags/UY.pngbin0 -> 2188 bytes
-rw-r--r--data/countryflags/UZ.pngbin0 -> 1385 bytes
-rw-r--r--data/countryflags/VA.pngbin0 -> 2547 bytes
-rw-r--r--data/countryflags/VC.pngbin0 -> 1495 bytes
-rw-r--r--data/countryflags/VE.pngbin0 -> 1342 bytes
-rw-r--r--data/countryflags/VG.pngbin0 -> 3211 bytes
-rw-r--r--data/countryflags/VI.pngbin0 -> 5088 bytes
-rw-r--r--data/countryflags/VN.pngbin0 -> 1278 bytes
-rw-r--r--data/countryflags/VU.pngbin0 -> 2410 bytes
-rw-r--r--data/countryflags/WF.pngbin0 -> 1263 bytes
-rw-r--r--data/countryflags/WS.pngbin0 -> 1216 bytes
-rw-r--r--data/countryflags/XEN.pngbin1192 -> 914 bytes
-rw-r--r--data/countryflags/XNI.pngbin3701 -> 2212 bytes
-rw-r--r--data/countryflags/XSC.pngbin3766 -> 2225 bytes
-rw-r--r--data/countryflags/XWA.pngbin6362 -> 4827 bytes
-rw-r--r--data/countryflags/YE.pngbin0 -> 699 bytes
-rw-r--r--data/countryflags/ZA.pngbin3270 -> 2255 bytes
-rw-r--r--data/countryflags/ZM.pngbin0 -> 1272 bytes
-rw-r--r--data/countryflags/ZW.pngbin0 -> 2070 bytes
-rw-r--r--data/countryflags/index.txt1534
-rw-r--r--data/editor/desert_main.rules227
-rw-r--r--data/editor/grass_main.rules225
-rw-r--r--data/editor/jungle_main.rules266
-rw-r--r--data/editor/winter_main.rules177
-rw-r--r--data/languages/belarusian.txt679
-rw-r--r--data/languages/bosnian.txt36
-rw-r--r--data/languages/brazilian_portuguese.txt679
-rw-r--r--data/languages/bulgarian.txt58
-rw-r--r--data/languages/czech.txt9
-rw-r--r--data/languages/dutch.txt28
-rw-r--r--data/languages/finnish.txt38
-rw-r--r--data/languages/hungarian.txt679
-rw-r--r--data/languages/index.txt32
-rw-r--r--data/languages/italian.txt235
-rw-r--r--data/languages/polish.txt489
-rw-r--r--data/languages/portuguese.txt210
-rw-r--r--data/languages/romanian.txt2
-rw-r--r--data/languages/russian.txt256
-rw-r--r--data/languages/serbian.txt432
-rw-r--r--data/languages/slovak.txt80
-rw-r--r--data/languages/spanish.txt216
-rw-r--r--data/languages/swedish.txt37
-rw-r--r--data/languages/ukrainian.txt16
-rw-r--r--other/sdl/vc2005libs/SDL.dllbin324096 -> 343552 bytes
-rw-r--r--other/sdl/vc2005libs/SDL.libbin42702 -> 42698 bytes
-rw-r--r--other/sdl/vc2005libs/SDLmain.libbin8264 -> 22852 bytes
-rw-r--r--scripts/cmd5.py2
-rw-r--r--src/base/system.c155
-rw-r--r--src/base/system.h12
-rw-r--r--src/engine/client.h1
-rw-r--r--src/engine/client/client.cpp234
-rw-r--r--src/engine/client/client.h35
-rw-r--r--src/engine/client/friends.cpp1
-rw-r--r--src/engine/client/graphics.cpp11
-rw-r--r--src/engine/console.h36
-rw-r--r--src/engine/masterserver.h1
-rw-r--r--src/engine/server.h2
-rw-r--r--src/engine/server/server.cpp198
-rw-r--r--src/engine/server/server.h23
-rw-r--r--src/engine/shared/config_variables.h12
-rw-r--r--src/engine/shared/console.cpp318
-rw-r--r--src/engine/shared/console.h34
-rw-r--r--src/engine/shared/datafile.cpp113
-rw-r--r--src/engine/shared/datafile.h16
-rw-r--r--src/engine/shared/econ.cpp173
-rw-r--r--src/engine/shared/econ.h50
-rw-r--r--src/engine/shared/filecollection.cpp186
-rw-r--r--src/engine/shared/filecollection.h35
-rw-r--r--src/engine/shared/masterserver.cpp90
-rw-r--r--src/engine/shared/network.h86
-rw-r--r--src/engine/shared/network_console.cpp219
-rw-r--r--src/engine/shared/network_console_conn.cpp186
-rw-r--r--src/engine/shared/network_server.cpp12
-rw-r--r--src/engine/shared/protocol.h6
-rw-r--r--src/game/client/components/console.cpp44
-rw-r--r--src/game/client/components/console.h7
-rw-r--r--src/game/client/components/countryflags.cpp1
-rw-r--r--src/game/client/components/countryflags.h3
-rw-r--r--src/game/client/components/emoticon.cpp8
-rw-r--r--src/game/client/components/hud.cpp4
-rw-r--r--src/game/client/components/maplayers.cpp6
-rw-r--r--src/game/client/components/menus.cpp6
-rw-r--r--src/game/client/components/menus_browser.cpp3
-rw-r--r--src/game/client/components/menus_settings.cpp51
-rw-r--r--src/game/client/components/spectator.cpp8
-rw-r--r--src/game/client/gameclient.cpp17
-rw-r--r--src/game/client/gameclient.h1
-rw-r--r--src/game/client/lineinput.cpp2
-rw-r--r--src/game/client/render.h5
-rw-r--r--src/game/client/render_map.cpp18
-rw-r--r--src/game/client/ui.cpp7
-rw-r--r--src/game/client/ui.h1
-rw-r--r--src/game/editor/auto_map.cpp202
-rw-r--r--src/game/editor/auto_map.h54
-rw-r--r--src/game/editor/editor.cpp393
-rw-r--r--src/game/editor/editor.h44
-rw-r--r--src/game/editor/io.cpp53
-rw-r--r--src/game/editor/layer_game.cpp2
-rw-r--r--src/game/editor/layer_quads.cpp22
-rw-r--r--src/game/editor/layer_tiles.cpp39
-rw-r--r--src/game/editor/popups.cpp74
-rw-r--r--src/game/gamecore.cpp48
-rw-r--r--src/game/mapitems.h9
-rw-r--r--src/game/server/entities/character.cpp2
-rw-r--r--src/game/server/gamecontext.cpp36
-rw-r--r--src/game/server/gamecontroller.cpp3
-rw-r--r--src/game/server/player.cpp6
-rw-r--r--src/game/variables.h3
-rw-r--r--src/game/version.h2
-rw-r--r--src/tools/dilate.cpp24
-rw-r--r--src/tools/tileset_borderfix.cpp24
337 files changed, 7623 insertions, 2496 deletions
diff --git a/data/countryflags/AD.png b/data/countryflags/AD.png
new file mode 100644
index 00000000..9977c009
--- /dev/null
+++ b/data/countryflags/AD.png
Binary files differdiff --git a/data/countryflags/AE.png b/data/countryflags/AE.png
new file mode 100644
index 00000000..7be66c75
--- /dev/null
+++ b/data/countryflags/AE.png
Binary files differdiff --git a/data/countryflags/AF.png b/data/countryflags/AF.png
new file mode 100644
index 00000000..e7f20d1c
--- /dev/null
+++ b/data/countryflags/AF.png
Binary files differdiff --git a/data/countryflags/AG.png b/data/countryflags/AG.png
new file mode 100644
index 00000000..22fdded8
--- /dev/null
+++ b/data/countryflags/AG.png
Binary files differdiff --git a/data/countryflags/AI.png b/data/countryflags/AI.png
new file mode 100644
index 00000000..9056a2b2
--- /dev/null
+++ b/data/countryflags/AI.png
Binary files differdiff --git a/data/countryflags/AL.png b/data/countryflags/AL.png
new file mode 100644
index 00000000..acc74619
--- /dev/null
+++ b/data/countryflags/AL.png
Binary files differdiff --git a/data/countryflags/AM.png b/data/countryflags/AM.png
new file mode 100644
index 00000000..139c30d9
--- /dev/null
+++ b/data/countryflags/AM.png
Binary files differdiff --git a/data/countryflags/AO.png b/data/countryflags/AO.png
new file mode 100644
index 00000000..5b3ca638
--- /dev/null
+++ b/data/countryflags/AO.png
Binary files differdiff --git a/data/countryflags/AR.png b/data/countryflags/AR.png
index 0ce5f92b..878458c7 100644
--- a/data/countryflags/AR.png
+++ b/data/countryflags/AR.png
Binary files differdiff --git a/data/countryflags/AS.png b/data/countryflags/AS.png
new file mode 100644
index 00000000..b4add724
--- /dev/null
+++ b/data/countryflags/AS.png
Binary files differdiff --git a/data/countryflags/AT.png b/data/countryflags/AT.png
index c1fbe9d4..13c6a599 100644
--- a/data/countryflags/AT.png
+++ b/data/countryflags/AT.png
Binary files differdiff --git a/data/countryflags/AU.png b/data/countryflags/AU.png
index 361f22e4..6e334645 100644
--- a/data/countryflags/AU.png
+++ b/data/countryflags/AU.png
Binary files differdiff --git a/data/countryflags/AW.png b/data/countryflags/AW.png
new file mode 100644
index 00000000..9c89e68c
--- /dev/null
+++ b/data/countryflags/AW.png
Binary files differdiff --git a/data/countryflags/AX.png b/data/countryflags/AX.png
new file mode 100644
index 00000000..d7fb2236
--- /dev/null
+++ b/data/countryflags/AX.png
Binary files differdiff --git a/data/countryflags/AZ.png b/data/countryflags/AZ.png
new file mode 100644
index 00000000..49bcb835
--- /dev/null
+++ b/data/countryflags/AZ.png
Binary files differdiff --git a/data/countryflags/BA.png b/data/countryflags/BA.png
index 3a77a439..21397f63 100644
--- a/data/countryflags/BA.png
+++ b/data/countryflags/BA.png
Binary files differdiff --git a/data/countryflags/BB.png b/data/countryflags/BB.png
new file mode 100644
index 00000000..051b3032
--- /dev/null
+++ b/data/countryflags/BB.png
Binary files differdiff --git a/data/countryflags/BD.png b/data/countryflags/BD.png
new file mode 100644
index 00000000..1488cf27
--- /dev/null
+++ b/data/countryflags/BD.png
Binary files differdiff --git a/data/countryflags/BE.png b/data/countryflags/BE.png
index 409e8552..b6135ec6 100644
--- a/data/countryflags/BE.png
+++ b/data/countryflags/BE.png
Binary files differdiff --git a/data/countryflags/BF.png b/data/countryflags/BF.png
new file mode 100644
index 00000000..fd1fa109
--- /dev/null
+++ b/data/countryflags/BF.png
Binary files differdiff --git a/data/countryflags/BG.png b/data/countryflags/BG.png
index 7f9a6590..f323e5d0 100644
--- a/data/countryflags/BG.png
+++ b/data/countryflags/BG.png
Binary files differdiff --git a/data/countryflags/BH.png b/data/countryflags/BH.png
new file mode 100644
index 00000000..59c8a487
--- /dev/null
+++ b/data/countryflags/BH.png
Binary files differdiff --git a/data/countryflags/BI.png b/data/countryflags/BI.png
new file mode 100644
index 00000000..08f0ec47
--- /dev/null
+++ b/data/countryflags/BI.png
Binary files differdiff --git a/data/countryflags/BJ.png b/data/countryflags/BJ.png
new file mode 100644
index 00000000..74725ce9
--- /dev/null
+++ b/data/countryflags/BJ.png
Binary files differdiff --git a/data/countryflags/BL.png b/data/countryflags/BL.png
new file mode 100644
index 00000000..692401bd
--- /dev/null
+++ b/data/countryflags/BL.png
Binary files differdiff --git a/data/countryflags/BM.png b/data/countryflags/BM.png
new file mode 100644
index 00000000..9d7cd871
--- /dev/null
+++ b/data/countryflags/BM.png
Binary files differdiff --git a/data/countryflags/BN.png b/data/countryflags/BN.png
new file mode 100644
index 00000000..38dd8cc9
--- /dev/null
+++ b/data/countryflags/BN.png
Binary files differdiff --git a/data/countryflags/BO.png b/data/countryflags/BO.png
new file mode 100644
index 00000000..028e1fe3
--- /dev/null
+++ b/data/countryflags/BO.png
Binary files differdiff --git a/data/countryflags/BR.png b/data/countryflags/BR.png
index aada91d5..5c2ea746 100644
--- a/data/countryflags/BR.png
+++ b/data/countryflags/BR.png
Binary files differdiff --git a/data/countryflags/BS.png b/data/countryflags/BS.png
new file mode 100644
index 00000000..aae921df
--- /dev/null
+++ b/data/countryflags/BS.png
Binary files differdiff --git a/data/countryflags/BT.png b/data/countryflags/BT.png
new file mode 100644
index 00000000..130b9045
--- /dev/null
+++ b/data/countryflags/BT.png
Binary files differdiff --git a/data/countryflags/BW.png b/data/countryflags/BW.png
new file mode 100644
index 00000000..d7782c6e
--- /dev/null
+++ b/data/countryflags/BW.png
Binary files differdiff --git a/data/countryflags/BY.png b/data/countryflags/BY.png
index 6052eea4..c05a3664 100644
--- a/data/countryflags/BY.png
+++ b/data/countryflags/BY.png
Binary files differdiff --git a/data/countryflags/BZ.png b/data/countryflags/BZ.png
new file mode 100644
index 00000000..93f832e5
--- /dev/null
+++ b/data/countryflags/BZ.png
Binary files differdiff --git a/data/countryflags/CA.png b/data/countryflags/CA.png
index 9898ba57..9d9f4a1e 100644
--- a/data/countryflags/CA.png
+++ b/data/countryflags/CA.png
Binary files differdiff --git a/data/countryflags/CC.png b/data/countryflags/CC.png
new file mode 100644
index 00000000..ef1b1dd2
--- /dev/null
+++ b/data/countryflags/CC.png
Binary files differdiff --git a/data/countryflags/CD.png b/data/countryflags/CD.png
new file mode 100644
index 00000000..3c5f2f95
--- /dev/null
+++ b/data/countryflags/CD.png
Binary files differdiff --git a/data/countryflags/CF.png b/data/countryflags/CF.png
new file mode 100644
index 00000000..e42de4dc
--- /dev/null
+++ b/data/countryflags/CF.png
Binary files differdiff --git a/data/countryflags/CG.png b/data/countryflags/CG.png
new file mode 100644
index 00000000..99a97ea1
--- /dev/null
+++ b/data/countryflags/CG.png
Binary files differdiff --git a/data/countryflags/CH.png b/data/countryflags/CH.png
index fa8d6482..27881d0c 100644
--- a/data/countryflags/CH.png
+++ b/data/countryflags/CH.png
Binary files differdiff --git a/data/countryflags/CI.png b/data/countryflags/CI.png
new file mode 100644
index 00000000..fa80f60b
--- /dev/null
+++ b/data/countryflags/CI.png
Binary files differdiff --git a/data/countryflags/CK.png b/data/countryflags/CK.png
new file mode 100644
index 00000000..c7a8d325
--- /dev/null
+++ b/data/countryflags/CK.png
Binary files differdiff --git a/data/countryflags/CL.png b/data/countryflags/CL.png
index 571851c7..327b27f6 100644
--- a/data/countryflags/CL.png
+++ b/data/countryflags/CL.png
Binary files differdiff --git a/data/countryflags/CM.png b/data/countryflags/CM.png
new file mode 100644
index 00000000..9e983e2d
--- /dev/null
+++ b/data/countryflags/CM.png
Binary files differdiff --git a/data/countryflags/CN.png b/data/countryflags/CN.png
index 3251bd9a..1996131e 100644
--- a/data/countryflags/CN.png
+++ b/data/countryflags/CN.png
Binary files differdiff --git a/data/countryflags/CO.png b/data/countryflags/CO.png
index 5fdda4a5..61f8fa55 100644
--- a/data/countryflags/CO.png
+++ b/data/countryflags/CO.png
Binary files differdiff --git a/data/countryflags/CR.png b/data/countryflags/CR.png
new file mode 100644
index 00000000..f6a02efd
--- /dev/null
+++ b/data/countryflags/CR.png
Binary files differdiff --git a/data/countryflags/CU.png b/data/countryflags/CU.png
new file mode 100644
index 00000000..0dbee8c2
--- /dev/null
+++ b/data/countryflags/CU.png
Binary files differdiff --git a/data/countryflags/CV.png b/data/countryflags/CV.png
new file mode 100644
index 00000000..95afe4b5
--- /dev/null
+++ b/data/countryflags/CV.png
Binary files differdiff --git a/data/countryflags/CW.png b/data/countryflags/CW.png
new file mode 100644
index 00000000..079ec877
--- /dev/null
+++ b/data/countryflags/CW.png
Binary files differdiff --git a/data/countryflags/CX.png b/data/countryflags/CX.png
new file mode 100644
index 00000000..12051034
--- /dev/null
+++ b/data/countryflags/CX.png
Binary files differdiff --git a/data/countryflags/CY.png b/data/countryflags/CY.png
new file mode 100644
index 00000000..dd34d6c4
--- /dev/null
+++ b/data/countryflags/CY.png
Binary files differdiff --git a/data/countryflags/CZ.png b/data/countryflags/CZ.png
index cb750877..b4df10db 100644
--- a/data/countryflags/CZ.png
+++ b/data/countryflags/CZ.png
Binary files differdiff --git a/data/countryflags/DE.png b/data/countryflags/DE.png
index 699a43d8..dde74c9e 100644
--- a/data/countryflags/DE.png
+++ b/data/countryflags/DE.png
Binary files differdiff --git a/data/countryflags/DJ.png b/data/countryflags/DJ.png
new file mode 100644
index 00000000..62a8c250
--- /dev/null
+++ b/data/countryflags/DJ.png
Binary files differdiff --git a/data/countryflags/DK.png b/data/countryflags/DK.png
index df04cf93..4125f604 100644
--- a/data/countryflags/DK.png
+++ b/data/countryflags/DK.png
Binary files differdiff --git a/data/countryflags/DM.png b/data/countryflags/DM.png
new file mode 100644
index 00000000..3ea6cf59
--- /dev/null
+++ b/data/countryflags/DM.png
Binary files differdiff --git a/data/countryflags/DO.png b/data/countryflags/DO.png
new file mode 100644
index 00000000..f70848f5
--- /dev/null
+++ b/data/countryflags/DO.png
Binary files differdiff --git a/data/countryflags/DZ.png b/data/countryflags/DZ.png
new file mode 100644
index 00000000..31df99f3
--- /dev/null
+++ b/data/countryflags/DZ.png
Binary files differdiff --git a/data/countryflags/EC.png b/data/countryflags/EC.png
new file mode 100644
index 00000000..80dfbaa2
--- /dev/null
+++ b/data/countryflags/EC.png
Binary files differdiff --git a/data/countryflags/EE.png b/data/countryflags/EE.png
index 45ef482f..6dc9933a 100644
--- a/data/countryflags/EE.png
+++ b/data/countryflags/EE.png
Binary files differdiff --git a/data/countryflags/EG.png b/data/countryflags/EG.png
index 3cd437d3..b0c3bf52 100644
--- a/data/countryflags/EG.png
+++ b/data/countryflags/EG.png
Binary files differdiff --git a/data/countryflags/EH.png b/data/countryflags/EH.png
new file mode 100644
index 00000000..9af42a3b
--- /dev/null
+++ b/data/countryflags/EH.png
Binary files differdiff --git a/data/countryflags/ER.png b/data/countryflags/ER.png
new file mode 100644
index 00000000..88dd0706
--- /dev/null
+++ b/data/countryflags/ER.png
Binary files differdiff --git a/data/countryflags/ES.png b/data/countryflags/ES.png
index b507a328..412b2107 100644
--- a/data/countryflags/ES.png
+++ b/data/countryflags/ES.png
Binary files differdiff --git a/data/countryflags/ET.png b/data/countryflags/ET.png
new file mode 100644
index 00000000..9588ce9a
--- /dev/null
+++ b/data/countryflags/ET.png
Binary files differdiff --git a/data/countryflags/FI.png b/data/countryflags/FI.png
index 96b39593..0373e03e 100644
--- a/data/countryflags/FI.png
+++ b/data/countryflags/FI.png
Binary files differdiff --git a/data/countryflags/FJ.png b/data/countryflags/FJ.png
new file mode 100644
index 00000000..9d2af629
--- /dev/null
+++ b/data/countryflags/FJ.png
Binary files differdiff --git a/data/countryflags/FK.png b/data/countryflags/FK.png
new file mode 100644
index 00000000..a3f2ad34
--- /dev/null
+++ b/data/countryflags/FK.png
Binary files differdiff --git a/data/countryflags/FM.png b/data/countryflags/FM.png
new file mode 100644
index 00000000..c0cd4cf1
--- /dev/null
+++ b/data/countryflags/FM.png
Binary files differdiff --git a/data/countryflags/FO.png b/data/countryflags/FO.png
new file mode 100644
index 00000000..e46c2eb3
--- /dev/null
+++ b/data/countryflags/FO.png
Binary files differdiff --git a/data/countryflags/FR.png b/data/countryflags/FR.png
index f85cfa49..eb4ec8ab 100644
--- a/data/countryflags/FR.png
+++ b/data/countryflags/FR.png
Binary files differdiff --git a/data/countryflags/GA.png b/data/countryflags/GA.png
new file mode 100644
index 00000000..446d380d
--- /dev/null
+++ b/data/countryflags/GA.png
Binary files differdiff --git a/data/countryflags/GB.png b/data/countryflags/GB.png
index 240adcc7..4aa46067 100644
--- a/data/countryflags/GB.png
+++ b/data/countryflags/GB.png
Binary files differdiff --git a/data/countryflags/GD.png b/data/countryflags/GD.png
new file mode 100644
index 00000000..538e8e09
--- /dev/null
+++ b/data/countryflags/GD.png
Binary files differdiff --git a/data/countryflags/GE.png b/data/countryflags/GE.png
new file mode 100644
index 00000000..67953847
--- /dev/null
+++ b/data/countryflags/GE.png
Binary files differdiff --git a/data/countryflags/GF.png b/data/countryflags/GF.png
new file mode 100644
index 00000000..2b804f54
--- /dev/null
+++ b/data/countryflags/GF.png
Binary files differdiff --git a/data/countryflags/GG.png b/data/countryflags/GG.png
new file mode 100644
index 00000000..472924fb
--- /dev/null
+++ b/data/countryflags/GG.png
Binary files differdiff --git a/data/countryflags/GH.png b/data/countryflags/GH.png
new file mode 100644
index 00000000..2809250f
--- /dev/null
+++ b/data/countryflags/GH.png
Binary files differdiff --git a/data/countryflags/GI.png b/data/countryflags/GI.png
new file mode 100644
index 00000000..9c88bfd4
--- /dev/null
+++ b/data/countryflags/GI.png
Binary files differdiff --git a/data/countryflags/GL.png b/data/countryflags/GL.png
new file mode 100644
index 00000000..6191d23c
--- /dev/null
+++ b/data/countryflags/GL.png
Binary files differdiff --git a/data/countryflags/GM.png b/data/countryflags/GM.png
new file mode 100644
index 00000000..ce94adfd
--- /dev/null
+++ b/data/countryflags/GM.png
Binary files differdiff --git a/data/countryflags/GN.png b/data/countryflags/GN.png
new file mode 100644
index 00000000..3f698559
--- /dev/null
+++ b/data/countryflags/GN.png
Binary files differdiff --git a/data/countryflags/GP.png b/data/countryflags/GP.png
new file mode 100644
index 00000000..bff1c31f
--- /dev/null
+++ b/data/countryflags/GP.png
Binary files differdiff --git a/data/countryflags/GQ.png b/data/countryflags/GQ.png
new file mode 100644
index 00000000..3a7dc2c5
--- /dev/null
+++ b/data/countryflags/GQ.png
Binary files differdiff --git a/data/countryflags/GR.png b/data/countryflags/GR.png
index 18eaeb28..a9dcd902 100644
--- a/data/countryflags/GR.png
+++ b/data/countryflags/GR.png
Binary files differdiff --git a/data/countryflags/GS.png b/data/countryflags/GS.png
new file mode 100644
index 00000000..bdeda46f
--- /dev/null
+++ b/data/countryflags/GS.png
Binary files differdiff --git a/data/countryflags/GT.png b/data/countryflags/GT.png
new file mode 100644
index 00000000..9ed9c11b
--- /dev/null
+++ b/data/countryflags/GT.png
Binary files differdiff --git a/data/countryflags/GU.png b/data/countryflags/GU.png
new file mode 100644
index 00000000..1a0affcd
--- /dev/null
+++ b/data/countryflags/GU.png
Binary files differdiff --git a/data/countryflags/GW.png b/data/countryflags/GW.png
new file mode 100644
index 00000000..b22b8d0e
--- /dev/null
+++ b/data/countryflags/GW.png
Binary files differdiff --git a/data/countryflags/GY.png b/data/countryflags/GY.png
new file mode 100644
index 00000000..35fd8c8f
--- /dev/null
+++ b/data/countryflags/GY.png
Binary files differdiff --git a/data/countryflags/HK.png b/data/countryflags/HK.png
new file mode 100644
index 00000000..6e4b18ce
--- /dev/null
+++ b/data/countryflags/HK.png
Binary files differdiff --git a/data/countryflags/HN.png b/data/countryflags/HN.png
new file mode 100644
index 00000000..09504718
--- /dev/null
+++ b/data/countryflags/HN.png
Binary files differdiff --git a/data/countryflags/HR.png b/data/countryflags/HR.png
index 6097adc7..c844d4f4 100644
--- a/data/countryflags/HR.png
+++ b/data/countryflags/HR.png
Binary files differdiff --git a/data/countryflags/HT.png b/data/countryflags/HT.png
new file mode 100644
index 00000000..3ab3e79f
--- /dev/null
+++ b/data/countryflags/HT.png
Binary files differdiff --git a/data/countryflags/HU.png b/data/countryflags/HU.png
index 20c21f0e..8106da42 100644
--- a/data/countryflags/HU.png
+++ b/data/countryflags/HU.png
Binary files differdiff --git a/data/countryflags/ID.png b/data/countryflags/ID.png
index 510bac08..49b52e3c 100644
--- a/data/countryflags/ID.png
+++ b/data/countryflags/ID.png
Binary files differdiff --git a/data/countryflags/IE.png b/data/countryflags/IE.png
new file mode 100644
index 00000000..df9be88f
--- /dev/null
+++ b/data/countryflags/IE.png
Binary files differdiff --git a/data/countryflags/IL.png b/data/countryflags/IL.png
index 3852a8f9..ce4acc73 100644
--- a/data/countryflags/IL.png
+++ b/data/countryflags/IL.png
Binary files differdiff --git a/data/countryflags/IM.png b/data/countryflags/IM.png
new file mode 100644
index 00000000..efd55fe4
--- /dev/null
+++ b/data/countryflags/IM.png
Binary files differdiff --git a/data/countryflags/IN.png b/data/countryflags/IN.png
index 91d34696..c4f8dbf0 100644
--- a/data/countryflags/IN.png
+++ b/data/countryflags/IN.png
Binary files differdiff --git a/data/countryflags/IO.png b/data/countryflags/IO.png
new file mode 100644
index 00000000..e983a3f2
--- /dev/null
+++ b/data/countryflags/IO.png
Binary files differdiff --git a/data/countryflags/IQ.png b/data/countryflags/IQ.png
new file mode 100644
index 00000000..81e7a8b4
--- /dev/null
+++ b/data/countryflags/IQ.png
Binary files differdiff --git a/data/countryflags/IR.png b/data/countryflags/IR.png
index 141a0e56..dcb71c3a 100644
--- a/data/countryflags/IR.png
+++ b/data/countryflags/IR.png
Binary files differdiff --git a/data/countryflags/IS.png b/data/countryflags/IS.png
new file mode 100644
index 00000000..4307fdfd
--- /dev/null
+++ b/data/countryflags/IS.png
Binary files differdiff --git a/data/countryflags/IT.png b/data/countryflags/IT.png
index 4d4a1b3e..7372d812 100644
--- a/data/countryflags/IT.png
+++ b/data/countryflags/IT.png
Binary files differdiff --git a/data/countryflags/JE.png b/data/countryflags/JE.png
new file mode 100644
index 00000000..a6b50b0c
--- /dev/null
+++ b/data/countryflags/JE.png
Binary files differdiff --git a/data/countryflags/JM.png b/data/countryflags/JM.png
new file mode 100644
index 00000000..94cf3abf
--- /dev/null
+++ b/data/countryflags/JM.png
Binary files differdiff --git a/data/countryflags/JO.png b/data/countryflags/JO.png
new file mode 100644
index 00000000..0bb6cb65
--- /dev/null
+++ b/data/countryflags/JO.png
Binary files differdiff --git a/data/countryflags/JP.png b/data/countryflags/JP.png
new file mode 100644
index 00000000..ddfdfb5c
--- /dev/null
+++ b/data/countryflags/JP.png
Binary files differdiff --git a/data/countryflags/KE.png b/data/countryflags/KE.png
new file mode 100644
index 00000000..e44c27d6
--- /dev/null
+++ b/data/countryflags/KE.png
Binary files differdiff --git a/data/countryflags/KG.png b/data/countryflags/KG.png
new file mode 100644
index 00000000..1c57fbbc
--- /dev/null
+++ b/data/countryflags/KG.png
Binary files differdiff --git a/data/countryflags/KH.png b/data/countryflags/KH.png
new file mode 100644
index 00000000..102bc024
--- /dev/null
+++ b/data/countryflags/KH.png
Binary files differdiff --git a/data/countryflags/KI.png b/data/countryflags/KI.png
new file mode 100644
index 00000000..7f62de60
--- /dev/null
+++ b/data/countryflags/KI.png
Binary files differdiff --git a/data/countryflags/KM.png b/data/countryflags/KM.png
new file mode 100644
index 00000000..f6a77ecc
--- /dev/null
+++ b/data/countryflags/KM.png
Binary files differdiff --git a/data/countryflags/KN.png b/data/countryflags/KN.png
new file mode 100644
index 00000000..06f6a9f9
--- /dev/null
+++ b/data/countryflags/KN.png
Binary files differdiff --git a/data/countryflags/KP.png b/data/countryflags/KP.png
new file mode 100644
index 00000000..48093061
--- /dev/null
+++ b/data/countryflags/KP.png
Binary files differdiff --git a/data/countryflags/KR.png b/data/countryflags/KR.png
new file mode 100644
index 00000000..32a83733
--- /dev/null
+++ b/data/countryflags/KR.png
Binary files differdiff --git a/data/countryflags/KW.png b/data/countryflags/KW.png
new file mode 100644
index 00000000..557e38b1
--- /dev/null
+++ b/data/countryflags/KW.png
Binary files differdiff --git a/data/countryflags/KY.png b/data/countryflags/KY.png
new file mode 100644
index 00000000..020dbeef
--- /dev/null
+++ b/data/countryflags/KY.png
Binary files differdiff --git a/data/countryflags/KZ.png b/data/countryflags/KZ.png
index e3db4f93..d0b6eede 100644
--- a/data/countryflags/KZ.png
+++ b/data/countryflags/KZ.png
Binary files differdiff --git a/data/countryflags/LA.png b/data/countryflags/LA.png
new file mode 100644
index 00000000..bfe966f6
--- /dev/null
+++ b/data/countryflags/LA.png
Binary files differdiff --git a/data/countryflags/LB.png b/data/countryflags/LB.png
new file mode 100644
index 00000000..3c8ef00c
--- /dev/null
+++ b/data/countryflags/LB.png
Binary files differdiff --git a/data/countryflags/LC.png b/data/countryflags/LC.png
new file mode 100644
index 00000000..19b5f78a
--- /dev/null
+++ b/data/countryflags/LC.png
Binary files differdiff --git a/data/countryflags/LI.png b/data/countryflags/LI.png
new file mode 100644
index 00000000..06daeeb8
--- /dev/null
+++ b/data/countryflags/LI.png
Binary files differdiff --git a/data/countryflags/LK.png b/data/countryflags/LK.png
new file mode 100644
index 00000000..f7710ae9
--- /dev/null
+++ b/data/countryflags/LK.png
Binary files differdiff --git a/data/countryflags/LR.png b/data/countryflags/LR.png
new file mode 100644
index 00000000..6d361dff
--- /dev/null
+++ b/data/countryflags/LR.png
Binary files differdiff --git a/data/countryflags/LS.png b/data/countryflags/LS.png
new file mode 100644
index 00000000..02a844fe
--- /dev/null
+++ b/data/countryflags/LS.png
Binary files differdiff --git a/data/countryflags/LT.png b/data/countryflags/LT.png
index dd1d3d13..c37e857f 100644
--- a/data/countryflags/LT.png
+++ b/data/countryflags/LT.png
Binary files differdiff --git a/data/countryflags/LU.png b/data/countryflags/LU.png
index 01377c56..ed89b616 100644
--- a/data/countryflags/LU.png
+++ b/data/countryflags/LU.png
Binary files differdiff --git a/data/countryflags/LV.png b/data/countryflags/LV.png
index 8915e25d..f5f51afc 100644
--- a/data/countryflags/LV.png
+++ b/data/countryflags/LV.png
Binary files differdiff --git a/data/countryflags/LY.png b/data/countryflags/LY.png
new file mode 100644
index 00000000..1dda0198
--- /dev/null
+++ b/data/countryflags/LY.png
Binary files differdiff --git a/data/countryflags/MA.png b/data/countryflags/MA.png
new file mode 100644
index 00000000..0ae330bb
--- /dev/null
+++ b/data/countryflags/MA.png
Binary files differdiff --git a/data/countryflags/MC.png b/data/countryflags/MC.png
new file mode 100644
index 00000000..5a73c3c1
--- /dev/null
+++ b/data/countryflags/MC.png
Binary files differdiff --git a/data/countryflags/MD.png b/data/countryflags/MD.png
new file mode 100644
index 00000000..d713b079
--- /dev/null
+++ b/data/countryflags/MD.png
Binary files differdiff --git a/data/countryflags/ME.png b/data/countryflags/ME.png
new file mode 100644
index 00000000..f6348bda
--- /dev/null
+++ b/data/countryflags/ME.png
Binary files differdiff --git a/data/countryflags/MF.png b/data/countryflags/MF.png
new file mode 100644
index 00000000..0fa201c9
--- /dev/null
+++ b/data/countryflags/MF.png
Binary files differdiff --git a/data/countryflags/MG.png b/data/countryflags/MG.png
new file mode 100644
index 00000000..52030837
--- /dev/null
+++ b/data/countryflags/MG.png
Binary files differdiff --git a/data/countryflags/MH.png b/data/countryflags/MH.png
new file mode 100644
index 00000000..40d7bd3d
--- /dev/null
+++ b/data/countryflags/MH.png
Binary files differdiff --git a/data/countryflags/MK.png b/data/countryflags/MK.png
new file mode 100644
index 00000000..3743d81a
--- /dev/null
+++ b/data/countryflags/MK.png
Binary files differdiff --git a/data/countryflags/ML.png b/data/countryflags/ML.png
new file mode 100644
index 00000000..d548a1e2
--- /dev/null
+++ b/data/countryflags/ML.png
Binary files differdiff --git a/data/countryflags/MM.png b/data/countryflags/MM.png
new file mode 100644
index 00000000..58c098b8
--- /dev/null
+++ b/data/countryflags/MM.png
Binary files differdiff --git a/data/countryflags/MN.png b/data/countryflags/MN.png
new file mode 100644
index 00000000..1d9f5159
--- /dev/null
+++ b/data/countryflags/MN.png
Binary files differdiff --git a/data/countryflags/MO.png b/data/countryflags/MO.png
new file mode 100644
index 00000000..6adda298
--- /dev/null
+++ b/data/countryflags/MO.png
Binary files differdiff --git a/data/countryflags/MP.png b/data/countryflags/MP.png
new file mode 100644
index 00000000..6b308645
--- /dev/null
+++ b/data/countryflags/MP.png
Binary files differdiff --git a/data/countryflags/MQ.png b/data/countryflags/MQ.png
new file mode 100644
index 00000000..2f3c556a
--- /dev/null
+++ b/data/countryflags/MQ.png
Binary files differdiff --git a/data/countryflags/MR.png b/data/countryflags/MR.png
new file mode 100644
index 00000000..8c6462ba
--- /dev/null
+++ b/data/countryflags/MR.png
Binary files differdiff --git a/data/countryflags/MS.png b/data/countryflags/MS.png
new file mode 100644
index 00000000..27312023
--- /dev/null
+++ b/data/countryflags/MS.png
Binary files differdiff --git a/data/countryflags/MT.png b/data/countryflags/MT.png
new file mode 100644
index 00000000..043ea73e
--- /dev/null
+++ b/data/countryflags/MT.png
Binary files differdiff --git a/data/countryflags/MU.png b/data/countryflags/MU.png
new file mode 100644
index 00000000..02a5f3af
--- /dev/null
+++ b/data/countryflags/MU.png
Binary files differdiff --git a/data/countryflags/MV.png b/data/countryflags/MV.png
new file mode 100644
index 00000000..6a3fd961
--- /dev/null
+++ b/data/countryflags/MV.png
Binary files differdiff --git a/data/countryflags/MW.png b/data/countryflags/MW.png
new file mode 100644
index 00000000..5d26e5f7
--- /dev/null
+++ b/data/countryflags/MW.png
Binary files differdiff --git a/data/countryflags/MX.png b/data/countryflags/MX.png
index 9505d623..19c7ddea 100644
--- a/data/countryflags/MX.png
+++ b/data/countryflags/MX.png
Binary files differdiff --git a/data/countryflags/MY.png b/data/countryflags/MY.png
new file mode 100644
index 00000000..885ba638
--- /dev/null
+++ b/data/countryflags/MY.png
Binary files differdiff --git a/data/countryflags/MZ.png b/data/countryflags/MZ.png
new file mode 100644
index 00000000..caa5cb4d
--- /dev/null
+++ b/data/countryflags/MZ.png
Binary files differdiff --git a/data/countryflags/NA.png b/data/countryflags/NA.png
new file mode 100644
index 00000000..f6936933
--- /dev/null
+++ b/data/countryflags/NA.png
Binary files differdiff --git a/data/countryflags/NC.png b/data/countryflags/NC.png
new file mode 100644
index 00000000..5f3b0892
--- /dev/null
+++ b/data/countryflags/NC.png
Binary files differdiff --git a/data/countryflags/NE.png b/data/countryflags/NE.png
new file mode 100644
index 00000000..7d73f48e
--- /dev/null
+++ b/data/countryflags/NE.png
Binary files differdiff --git a/data/countryflags/NF.png b/data/countryflags/NF.png
new file mode 100644
index 00000000..5f5401d7
--- /dev/null
+++ b/data/countryflags/NF.png
Binary files differdiff --git a/data/countryflags/NG.png b/data/countryflags/NG.png
new file mode 100644
index 00000000..e9030716
--- /dev/null
+++ b/data/countryflags/NG.png
Binary files differdiff --git a/data/countryflags/NI.png b/data/countryflags/NI.png
new file mode 100644
index 00000000..19df0e95
--- /dev/null
+++ b/data/countryflags/NI.png
Binary files differdiff --git a/data/countryflags/NL.png b/data/countryflags/NL.png
index 5882be49..ba54b03c 100644
--- a/data/countryflags/NL.png
+++ b/data/countryflags/NL.png
Binary files differdiff --git a/data/countryflags/NO.png b/data/countryflags/NO.png
index 2e9bbec9..6f085323 100644
--- a/data/countryflags/NO.png
+++ b/data/countryflags/NO.png
Binary files differdiff --git a/data/countryflags/NP.png b/data/countryflags/NP.png
new file mode 100644
index 00000000..53c7510a
--- /dev/null
+++ b/data/countryflags/NP.png
Binary files differdiff --git a/data/countryflags/NR.png b/data/countryflags/NR.png
new file mode 100644
index 00000000..562be4fc
--- /dev/null
+++ b/data/countryflags/NR.png
Binary files differdiff --git a/data/countryflags/NU.png b/data/countryflags/NU.png
new file mode 100644
index 00000000..1928bab6
--- /dev/null
+++ b/data/countryflags/NU.png
Binary files differdiff --git a/data/countryflags/NZ.png b/data/countryflags/NZ.png
new file mode 100644
index 00000000..4e210491
--- /dev/null
+++ b/data/countryflags/NZ.png
Binary files differdiff --git a/data/countryflags/OM.png b/data/countryflags/OM.png
new file mode 100644
index 00000000..8b6aba47
--- /dev/null
+++ b/data/countryflags/OM.png
Binary files differdiff --git a/data/countryflags/PA.png b/data/countryflags/PA.png
new file mode 100644
index 00000000..ef051c61
--- /dev/null
+++ b/data/countryflags/PA.png
Binary files differdiff --git a/data/countryflags/PE.png b/data/countryflags/PE.png
new file mode 100644
index 00000000..f6188650
--- /dev/null
+++ b/data/countryflags/PE.png
Binary files differdiff --git a/data/countryflags/PF.png b/data/countryflags/PF.png
new file mode 100644
index 00000000..bf04554d
--- /dev/null
+++ b/data/countryflags/PF.png
Binary files differdiff --git a/data/countryflags/PG.png b/data/countryflags/PG.png
new file mode 100644
index 00000000..04b36a38
--- /dev/null
+++ b/data/countryflags/PG.png
Binary files differdiff --git a/data/countryflags/PH.png b/data/countryflags/PH.png
index ebcec1f2..edb506c0 100644
--- a/data/countryflags/PH.png
+++ b/data/countryflags/PH.png
Binary files differdiff --git a/data/countryflags/PK.png b/data/countryflags/PK.png
index 6e4e4950..6030b86b 100644
--- a/data/countryflags/PK.png
+++ b/data/countryflags/PK.png
Binary files differdiff --git a/data/countryflags/PL.png b/data/countryflags/PL.png
index 6e6a5c95..03b9e71f 100644
--- a/data/countryflags/PL.png
+++ b/data/countryflags/PL.png
Binary files differdiff --git a/data/countryflags/PM.png b/data/countryflags/PM.png
new file mode 100644
index 00000000..dd0dce93
--- /dev/null
+++ b/data/countryflags/PM.png
Binary files differdiff --git a/data/countryflags/PN.png b/data/countryflags/PN.png
new file mode 100644
index 00000000..a14628bb
--- /dev/null
+++ b/data/countryflags/PN.png
Binary files differdiff --git a/data/countryflags/PR.png b/data/countryflags/PR.png
new file mode 100644
index 00000000..6a3f6014
--- /dev/null
+++ b/data/countryflags/PR.png
Binary files differdiff --git a/data/countryflags/PT.png b/data/countryflags/PT.png
index b3be0973..ca90e6e9 100644
--- a/data/countryflags/PT.png
+++ b/data/countryflags/PT.png
Binary files differdiff --git a/data/countryflags/PW.png b/data/countryflags/PW.png
new file mode 100644
index 00000000..49ee4480
--- /dev/null
+++ b/data/countryflags/PW.png
Binary files differdiff --git a/data/countryflags/PY.png b/data/countryflags/PY.png
new file mode 100644
index 00000000..948f7151
--- /dev/null
+++ b/data/countryflags/PY.png
Binary files differdiff --git a/data/countryflags/QA.png b/data/countryflags/QA.png
new file mode 100644
index 00000000..cae22d2b
--- /dev/null
+++ b/data/countryflags/QA.png
Binary files differdiff --git a/data/countryflags/RE.png b/data/countryflags/RE.png
new file mode 100644
index 00000000..5efe1da4
--- /dev/null
+++ b/data/countryflags/RE.png
Binary files differdiff --git a/data/countryflags/RO.png b/data/countryflags/RO.png
index 4eae6d22..6ea76a88 100644
--- a/data/countryflags/RO.png
+++ b/data/countryflags/RO.png
Binary files differdiff --git a/data/countryflags/RS.png b/data/countryflags/RS.png
index 7cc06394..24e067b4 100644
--- a/data/countryflags/RS.png
+++ b/data/countryflags/RS.png
Binary files differdiff --git a/data/countryflags/RU.png b/data/countryflags/RU.png
index ed293810..74a8528f 100644
--- a/data/countryflags/RU.png
+++ b/data/countryflags/RU.png
Binary files differdiff --git a/data/countryflags/RW.png b/data/countryflags/RW.png
new file mode 100644
index 00000000..57d3ac5f
--- /dev/null
+++ b/data/countryflags/RW.png
Binary files differdiff --git a/data/countryflags/SA.png b/data/countryflags/SA.png
index fbfb6cf5..93598245 100644
--- a/data/countryflags/SA.png
+++ b/data/countryflags/SA.png
Binary files differdiff --git a/data/countryflags/SB.png b/data/countryflags/SB.png
new file mode 100644
index 00000000..7c4c468d
--- /dev/null
+++ b/data/countryflags/SB.png
Binary files differdiff --git a/data/countryflags/SC.png b/data/countryflags/SC.png
new file mode 100644
index 00000000..5237f2e8
--- /dev/null
+++ b/data/countryflags/SC.png
Binary files differdiff --git a/data/countryflags/SD.png b/data/countryflags/SD.png
new file mode 100644
index 00000000..6adab5ad
--- /dev/null
+++ b/data/countryflags/SD.png
Binary files differdiff --git a/data/countryflags/SE.png b/data/countryflags/SE.png
index c5c9cda9..47dcef3f 100644
--- a/data/countryflags/SE.png
+++ b/data/countryflags/SE.png
Binary files differdiff --git a/data/countryflags/SG.png b/data/countryflags/SG.png
new file mode 100644
index 00000000..c54a7608
--- /dev/null
+++ b/data/countryflags/SG.png
Binary files differdiff --git a/data/countryflags/SH.png b/data/countryflags/SH.png
new file mode 100644
index 00000000..a9b6fc9f
--- /dev/null
+++ b/data/countryflags/SH.png
Binary files differdiff --git a/data/countryflags/SI.png b/data/countryflags/SI.png
new file mode 100644
index 00000000..1e553fd5
--- /dev/null
+++ b/data/countryflags/SI.png
Binary files differdiff --git a/data/countryflags/SK.png b/data/countryflags/SK.png
index 5bd535a1..9c927e8f 100644
--- a/data/countryflags/SK.png
+++ b/data/countryflags/SK.png
Binary files differdiff --git a/data/countryflags/SL.png b/data/countryflags/SL.png
new file mode 100644
index 00000000..5d1d42fe
--- /dev/null
+++ b/data/countryflags/SL.png
Binary files differdiff --git a/data/countryflags/SM.png b/data/countryflags/SM.png
new file mode 100644
index 00000000..96726305
--- /dev/null
+++ b/data/countryflags/SM.png
Binary files differdiff --git a/data/countryflags/SN.png b/data/countryflags/SN.png
new file mode 100644
index 00000000..42a57326
--- /dev/null
+++ b/data/countryflags/SN.png
Binary files differdiff --git a/data/countryflags/SO.png b/data/countryflags/SO.png
new file mode 100644
index 00000000..93815d27
--- /dev/null
+++ b/data/countryflags/SO.png
Binary files differdiff --git a/data/countryflags/SR.png b/data/countryflags/SR.png
new file mode 100644
index 00000000..06fe40f3
--- /dev/null
+++ b/data/countryflags/SR.png
Binary files differdiff --git a/data/countryflags/SS.png b/data/countryflags/SS.png
new file mode 100644
index 00000000..203c51da
--- /dev/null
+++ b/data/countryflags/SS.png
Binary files differdiff --git a/data/countryflags/ST.png b/data/countryflags/ST.png
new file mode 100644
index 00000000..748030a0
--- /dev/null
+++ b/data/countryflags/ST.png
Binary files differdiff --git a/data/countryflags/SV.png b/data/countryflags/SV.png
index d313b0c1..d03b8be4 100644
--- a/data/countryflags/SV.png
+++ b/data/countryflags/SV.png
Binary files differdiff --git a/data/countryflags/SX.png b/data/countryflags/SX.png
new file mode 100644
index 00000000..61606935
--- /dev/null
+++ b/data/countryflags/SX.png
Binary files differdiff --git a/data/countryflags/SY.png b/data/countryflags/SY.png
new file mode 100644
index 00000000..04342871
--- /dev/null
+++ b/data/countryflags/SY.png
Binary files differdiff --git a/data/countryflags/SZ.png b/data/countryflags/SZ.png
new file mode 100644
index 00000000..bea99b2c
--- /dev/null
+++ b/data/countryflags/SZ.png
Binary files differdiff --git a/data/countryflags/TC.png b/data/countryflags/TC.png
new file mode 100644
index 00000000..0abdc845
--- /dev/null
+++ b/data/countryflags/TC.png
Binary files differdiff --git a/data/countryflags/TD.png b/data/countryflags/TD.png
new file mode 100644
index 00000000..4ffcc670
--- /dev/null
+++ b/data/countryflags/TD.png
Binary files differdiff --git a/data/countryflags/TF.png b/data/countryflags/TF.png
new file mode 100644
index 00000000..d3095b29
--- /dev/null
+++ b/data/countryflags/TF.png
Binary files differdiff --git a/data/countryflags/TG.png b/data/countryflags/TG.png
new file mode 100644
index 00000000..797f48cd
--- /dev/null
+++ b/data/countryflags/TG.png
Binary files differdiff --git a/data/countryflags/TH.png b/data/countryflags/TH.png
new file mode 100644
index 00000000..97e22df3
--- /dev/null
+++ b/data/countryflags/TH.png
Binary files differdiff --git a/data/countryflags/TJ.png b/data/countryflags/TJ.png
new file mode 100644
index 00000000..54d9830f
--- /dev/null
+++ b/data/countryflags/TJ.png
Binary files differdiff --git a/data/countryflags/TK.png b/data/countryflags/TK.png
new file mode 100644
index 00000000..623f69e0
--- /dev/null
+++ b/data/countryflags/TK.png
Binary files differdiff --git a/data/countryflags/TL.png b/data/countryflags/TL.png
new file mode 100644
index 00000000..5c6f1ff7
--- /dev/null
+++ b/data/countryflags/TL.png
Binary files differdiff --git a/data/countryflags/TM.png b/data/countryflags/TM.png
new file mode 100644
index 00000000..40767589
--- /dev/null
+++ b/data/countryflags/TM.png
Binary files differdiff --git a/data/countryflags/TN.png b/data/countryflags/TN.png
new file mode 100644
index 00000000..10f9f696
--- /dev/null
+++ b/data/countryflags/TN.png
Binary files differdiff --git a/data/countryflags/TO.png b/data/countryflags/TO.png
new file mode 100644
index 00000000..a7a703c9
--- /dev/null
+++ b/data/countryflags/TO.png
Binary files differdiff --git a/data/countryflags/TR.png b/data/countryflags/TR.png
index 8bc78a72..2df563de 100644
--- a/data/countryflags/TR.png
+++ b/data/countryflags/TR.png
Binary files differdiff --git a/data/countryflags/TT.png b/data/countryflags/TT.png
new file mode 100644
index 00000000..c3f21b2b
--- /dev/null
+++ b/data/countryflags/TT.png
Binary files differdiff --git a/data/countryflags/TV.png b/data/countryflags/TV.png
new file mode 100644
index 00000000..ede2dbca
--- /dev/null
+++ b/data/countryflags/TV.png
Binary files differdiff --git a/data/countryflags/TW.png b/data/countryflags/TW.png
new file mode 100644
index 00000000..e3c48eb2
--- /dev/null
+++ b/data/countryflags/TW.png
Binary files differdiff --git a/data/countryflags/TZ.png b/data/countryflags/TZ.png
new file mode 100644
index 00000000..38ad129d
--- /dev/null
+++ b/data/countryflags/TZ.png
Binary files differdiff --git a/data/countryflags/UA.png b/data/countryflags/UA.png
index 1356e7cb..f9fc86cd 100644
--- a/data/countryflags/UA.png
+++ b/data/countryflags/UA.png
Binary files differdiff --git a/data/countryflags/UG.png b/data/countryflags/UG.png
new file mode 100644
index 00000000..92537e9b
--- /dev/null
+++ b/data/countryflags/UG.png
Binary files differdiff --git a/data/countryflags/US.png b/data/countryflags/US.png
index 96dfca89..448930c2 100644
--- a/data/countryflags/US.png
+++ b/data/countryflags/US.png
Binary files differdiff --git a/data/countryflags/UY.png b/data/countryflags/UY.png
new file mode 100644
index 00000000..4c950068
--- /dev/null
+++ b/data/countryflags/UY.png
Binary files differdiff --git a/data/countryflags/UZ.png b/data/countryflags/UZ.png
new file mode 100644
index 00000000..0689f217
--- /dev/null
+++ b/data/countryflags/UZ.png
Binary files differdiff --git a/data/countryflags/VA.png b/data/countryflags/VA.png
new file mode 100644
index 00000000..e957e06d
--- /dev/null
+++ b/data/countryflags/VA.png
Binary files differdiff --git a/data/countryflags/VC.png b/data/countryflags/VC.png
new file mode 100644
index 00000000..60f90b55
--- /dev/null
+++ b/data/countryflags/VC.png
Binary files differdiff --git a/data/countryflags/VE.png b/data/countryflags/VE.png
new file mode 100644
index 00000000..e36f7a4b
--- /dev/null
+++ b/data/countryflags/VE.png
Binary files differdiff --git a/data/countryflags/VG.png b/data/countryflags/VG.png
new file mode 100644
index 00000000..99069e25
--- /dev/null
+++ b/data/countryflags/VG.png
Binary files differdiff --git a/data/countryflags/VI.png b/data/countryflags/VI.png
new file mode 100644
index 00000000..05fa911a
--- /dev/null
+++ b/data/countryflags/VI.png
Binary files differdiff --git a/data/countryflags/VN.png b/data/countryflags/VN.png
new file mode 100644
index 00000000..c4e19d79
--- /dev/null
+++ b/data/countryflags/VN.png
Binary files differdiff --git a/data/countryflags/VU.png b/data/countryflags/VU.png
new file mode 100644
index 00000000..228083ba
--- /dev/null
+++ b/data/countryflags/VU.png
Binary files differdiff --git a/data/countryflags/WF.png b/data/countryflags/WF.png
new file mode 100644
index 00000000..aeeba249
--- /dev/null
+++ b/data/countryflags/WF.png
Binary files differdiff --git a/data/countryflags/WS.png b/data/countryflags/WS.png
new file mode 100644
index 00000000..5d16a5d9
--- /dev/null
+++ b/data/countryflags/WS.png
Binary files differdiff --git a/data/countryflags/XEN.png b/data/countryflags/XEN.png
index 8388316c..08e3ef29 100644
--- a/data/countryflags/XEN.png
+++ b/data/countryflags/XEN.png
Binary files differdiff --git a/data/countryflags/XNI.png b/data/countryflags/XNI.png
index 410615b0..18083db0 100644
--- a/data/countryflags/XNI.png
+++ b/data/countryflags/XNI.png
Binary files differdiff --git a/data/countryflags/XSC.png b/data/countryflags/XSC.png
index f3b9ee03..3002fd50 100644
--- a/data/countryflags/XSC.png
+++ b/data/countryflags/XSC.png
Binary files differdiff --git a/data/countryflags/XWA.png b/data/countryflags/XWA.png
index bae3809e..3b6b86be 100644
--- a/data/countryflags/XWA.png
+++ b/data/countryflags/XWA.png
Binary files differdiff --git a/data/countryflags/YE.png b/data/countryflags/YE.png
new file mode 100644
index 00000000..73686007
--- /dev/null
+++ b/data/countryflags/YE.png
Binary files differdiff --git a/data/countryflags/ZA.png b/data/countryflags/ZA.png
index c7e30de0..21aec1ed 100644
--- a/data/countryflags/ZA.png
+++ b/data/countryflags/ZA.png
Binary files differdiff --git a/data/countryflags/ZM.png b/data/countryflags/ZM.png
new file mode 100644
index 00000000..2160d527
--- /dev/null
+++ b/data/countryflags/ZM.png
Binary files differdiff --git a/data/countryflags/ZW.png b/data/countryflags/ZW.png
new file mode 100644
index 00000000..b6c870ca
--- /dev/null
+++ b/data/countryflags/ZW.png
Binary files differdiff --git a/data/countryflags/index.txt b/data/countryflags/index.txt
index f841c194..3b60f1b2 100644
--- a/data/countryflags/index.txt
+++ b/data/countryflags/index.txt
@@ -1,765 +1,769 @@
-
-##### country codes #####
-
-##### custom #####
-
-default
-== -1
-
-XEN
-== 901
-
-XNI
-== 902
-
-XSC
-== 903
-
-XWA
-== 904
-
-##### ISO 3166-1 based #####
-
-#AF
-#== 4
-
-#AX
-#== 248
-
-#AL
-#== 8
-
-#DZ
-#== 12
-
-#AS
-#== 16
-
-#AD
-#== 20
-
-#AO
-#== 24
-
-#AI
-#== 660
-
-#AQ
-#== 10
-
-#AG
-#== 28
-
-AR
-== 32
-
-#AM
-#== 51
-
-#AW
-#== 533
-
-AU
-== 36
-
-AT
-== 40
-
-#AZ
-#== 31
-
-#BS
-#== 44
-
-#BH
-#== 48
-
-#BD
-#== 50
-
-#BB
-#== 52
-
-BY
-== 112
-
-BE
-== 56
-
-#BZ
-#== 84
-
-#BJ
-#== 204
-
-#BM
-#== 60
-
-#BT
-#== 64
-
-#BO
-#== 68
-
-#BQ
-#== 535
-
-BA
-== 70
-
-#BW
-#== 72
-
-#BV
-#== 74
-
-BR
-== 76
-
-#IO
-#== 86
-
-#BN
-#== 96
-
-BG
-== 100
-
-#BF
-#== 854
-
-#BI
-#== 108
-
-#KH
-#== 116
-
-#CM
-#== 120
-
-CA
-== 124
-
-#CV
-#== 132
-
-#KY
-#== 136
-
-#CF
-#== 140
-
-#TD
-#== 148
-
-CL
-== 152
-
-CN
-== 156
-
-#CX
-#== 162
-
-#CC
-#== 166
-
-CO
-== 170
-
-#KM
-#== 174
-
-#CG
-#== 178
-
-#CD
-#== 180
-
-#CK
-#== 184
-
-#CR
-#== 188
-
-#CI
-#== 384
-
-HR
-== 191
-
-#CU
-#== 192
-
-#CW
-#== 531
-
-#CY
-#== 196
-
-CZ
-== 203
-
-DK
-== 208
-
-#DJ
-#== 262
-
-#DM
-#== 212
-
-#DO
-#== 214
-
-#EC
-#== 218
-
-EG
-== 818
-
-SV
-== 222
-
-#GQ
-#== 226
-
-#ER
-#== 232
-
-EE
-== 233
-
-#ET
-#== 231
-
-#FK
-#== 238
-
-#FO
-#== 234
-
-#FJ
-#== 242
-
-FI
-== 246
-
-FR
-== 250
-
-#GF
-#== 254
-
-#PF
-#== 258
-
-#TF
-#== 260
-
-#GA
-#== 266
-
-#GM
-#== 270
-
-#GE
-#== 268
-
-DE
-== 276
-
-#GH
-#== 288
-
-#GI
-#== 292
-
-GR
-== 300
-
-#GL
-#== 304
-
-#GD
-#== 308
-
-#GP
-#== 312
-
-#GU
-#== 316
-
-#GT
-#== 320
-
-#GG
-#== 831
-
-#GN
-#== 324
-
-#GW
-#== 624
-
-#GY
-#== 328
-
-#HT
-#== 332
-
-#HM
-#== 334
-
-#VA
-#== 336
-
-#HN
-#== 340
-
-#HK
-#== 344
-
-HU
-== 348
-
-#IS
-#== 352
-
-IN
-== 356
-
-ID
-== 360
-
-IR
-== 364
-
-#IQ
-#== 368
-
-#IE
-#== 372
-
-#IM
-#== 833
-
-IL
-== 376
-
-IT
-== 380
-
-#JM
-#== 388
-
-#JP
-#== 392
-
-#JE
-#== 832
-
-#JO
-#== 400
-
-KZ
-== 398
-
-#KE
-#== 404
-
-#KI
-#== 296
-
-#KP
-#== 408
-
-#KR
-#== 410
-
-#KW
-#== 414
-
-#KG
-#== 417
-
-#LA
-#== 418
-
-LV
-== 428
-
-#LB
-#== 422
-
-#LS
-#== 426
-
-#LR
-#== 430
-
-#LY
-#== 434
-
-#LI
-#== 438
-
-LT
-== 440
-
-LU
-== 442
-
-#MO
-#== 446
-
-#MK
-#== 807
-
-#MG
-#== 450
-
-#MW
-#== 454
-
-#MY
-#== 458
-
-#MV
-#== 462
-
-#ML
-#== 466
-
-#MT
-#== 470
-
-#MH
-#== 584
-
-#MQ
-#== 474
-
-#MR
-#== 478
-
-#MU
-#== 480
-
-#YT
-#== 175
-
-MX
-== 484
-
-#FM
-#== 583
-
-#MD
-#== 498
-
-#MC
-#== 492
-
-#MN
-#== 496
-
-#ME
-#== 499
-
-#MS
-#== 500
-
-#MA
-#== 504
-
-#MZ
-#== 508
-
-#MM
-#== 104
-
-#NA
-#== 516
-
-#NR
-#== 520
-
-#NP
-#== 524
-
-NL
-== 528
-
-#NC
-#== 540
-
-#NZ
-#== 554
-
-#NI
-#== 558
-
-#NE
-#== 562
-
-#NG
-#== 566
-
-#NU
-#== 570
-
-#NF
-#== 574
-
-#MP
-#== 580
-
-NO
-== 578
-
-#OM
-#== 512
-
-PK
-== 586
-
-#PW
-#== 585
-
-#PS
-#== 275
-
-#PA
-#== 591
-
-#PG
-#== 598
-
-#PY
-#== 600
-
-#PE
-#== 604
-
-PH
-== 608
-
-#PN
-#== 612
-
-PL
-== 616
-
-PT
-== 620
-
-#PR
-#== 630
-
-#QA
-#== 634
-
-#RE
-#== 638
-
-RO
-== 642
-
-RU
-== 643
-
-#RW
-#== 646
-
-#BL
-#== 652
-
-#SH
-#== 654
-
-#KN
-#== 659
-
-#LC
-#== 662
-
-#MF
-#== 663
-
-#PM
-#== 666
-
-#VC
-#== 670
-
-#WS
-#== 882
-
-#SM
-#== 674
-
-#ST
-#== 678
-
-SA
-== 682
-
-#SN
-#== 686
-
-RS
-== 688
-
-#SC
-#== 690
-
-#SL
-#== 694
-
-#SG
-#== 702
-
-#SX
-#== 534
-
-SK
-== 703
-
-#SI
-#== 705
-
-#SB
-#== 90
-
-#SO
-#== 706
-
-ZA
-== 710
-
-#GS
-#== 239
-
-ES
-== 724
-
-#LK
-#== 144
-
-#SD
-#== 736
-
-#SR
-#== 740
-
-#SJ
-#== 744
-
-#SZ
-#== 748
-
-SE
-== 752
-
-CH
-== 756
-
-#SY
-#== 760
-
-#TW
-#== 158
-
-#TJ
-#== 762
-
-#TZ
-#== 834
-
-#TH
-#== 764
-
-#TL
-#== 626
-
-#TG
-#== 768
-
-#TK
-#== 772
-
-#TO
-#== 776
-
-#TT
-#== 780
-
-#TN
-#== 788
-
-TR
-== 792
-
-#TM
-#== 795
-
-#TC
-#== 796
-
-#TV
-#== 798
-
-#UG
-#== 800
-
-UA
-== 804
-
-#AE
-#== 784
-
-GB
-== 826
-
-US
-== 840
-
-#UM
-#== 581
-
-#UY
-#== 858
-
-#UZ
-#== 860
-
-#VU
-#== 548
-
-#VE
-#== 862
-
-#VN
-#== 704
-
-#VG
-#== 92
-
-#VI
-#== 850
-
-#WF
-#== 876
-
-#EH
-#== 732
-
-#YE
-#== 887
-
-#ZM
-#== 894
-
-#ZW
-#== 716
+

+##### country codes #####

+

+##### custom #####

+

+default

+== -1

+

+XEN

+== 901

+

+XNI

+== 902

+

+XSC

+== 903

+

+XWA

+== 904

+

+#south sudan, non official code#

+SS

+== 737

+

+##### ISO 3166-1 based #####

+

+AF

+== 4

+

+AX

+== 248

+

+AL

+== 8

+

+DZ

+== 12

+

+AS

+== 16

+

+AD

+== 20

+

+AO

+== 24

+

+AI

+== 660

+

+#AQ

+#== 10

+

+AG

+== 28

+

+AR

+== 32

+

+AM

+== 51

+

+AW

+== 533

+

+AU

+== 36

+

+AT

+== 40

+

+AZ

+== 31

+

+BS

+== 44

+

+BH

+== 48

+

+BD

+== 50

+

+BB

+== 52

+

+BY

+== 112

+

+BE

+== 56

+

+BZ

+== 84

+

+BJ

+== 204

+

+BM

+== 60

+

+BT

+== 64

+

+BO

+== 68

+

+#BQ

+#== 535

+

+BA

+== 70

+

+BW

+== 72

+

+#BV

+#== 74

+

+BR

+== 76

+

+IO

+== 86

+

+BN

+== 96

+

+BG

+== 100

+

+BF

+== 854

+

+BI

+== 108

+

+KH

+== 116

+

+CM

+== 120

+

+CA

+== 124

+

+CV

+== 132

+

+KY

+== 136

+

+CF

+== 140

+

+TD

+== 148

+

+CL

+== 152

+

+CN

+== 156

+

+CX

+== 162

+

+CC

+== 166

+

+CO

+== 170

+

+KM

+== 174

+

+CG

+== 178

+

+CD

+== 180

+

+CK

+== 184

+

+CR

+== 188

+

+CI

+== 384

+

+HR

+== 191

+

+CU

+== 192

+

+CW

+== 531

+

+CY

+== 196

+

+CZ

+== 203

+

+DK

+== 208

+

+DJ

+== 262

+

+DM

+== 212

+

+DO

+== 214

+

+EC

+== 218

+

+EG

+== 818

+

+SV

+== 222

+

+GQ

+== 226

+

+ER

+== 232

+

+EE

+== 233

+

+ET

+== 231

+

+FK

+== 238

+

+FO

+== 234

+

+FJ

+== 242

+

+FI

+== 246

+

+FR

+== 250

+

+GF

+== 254

+

+PF

+== 258

+

+TF

+== 260

+

+GA

+== 266

+

+GM

+== 270

+

+GE

+== 268

+

+DE

+== 276

+

+GH

+== 288

+

+GI

+== 292

+

+GR

+== 300

+

+GL

+== 304

+

+GD

+== 308

+

+GP

+== 312

+

+GU

+== 316

+

+GT

+== 320

+

+GG

+== 831

+

+GN

+== 324

+

+GW

+== 624

+

+GY

+== 328

+

+HT

+== 332

+

+#HM

+#== 334

+

+VA

+== 336

+

+HN

+== 340

+

+HK

+== 344

+

+HU

+== 348

+

+IS

+== 352

+

+IN

+== 356

+

+ID

+== 360

+

+IR

+== 364

+

+IQ

+== 368

+

+IE

+== 372

+

+IM

+== 833

+

+IL

+== 376

+

+IT

+== 380

+

+JM

+== 388

+

+JP

+== 392

+

+JE

+== 832

+

+JO

+== 400

+

+KZ

+== 398

+

+KE

+== 404

+

+KI

+== 296

+

+KP

+== 408

+

+KR

+== 410

+

+KW

+== 414

+

+KG

+== 417

+

+LA

+== 418

+

+LV

+== 428

+

+LB

+== 422

+

+LS

+== 426

+

+LR

+== 430

+

+LY

+== 434

+

+LI

+== 438

+

+LT

+== 440

+

+LU

+== 442

+

+MO

+== 446

+

+MK

+== 807

+

+MG

+== 450

+

+MW

+== 454

+

+MY

+== 458

+

+MV

+== 462

+

+ML

+== 466

+

+MT

+== 470

+

+MH

+== 584

+

+MQ

+== 474

+

+MR

+== 478

+

+MU

+== 480

+

+#YT

+#== 175

+

+MX

+== 484

+

+FM

+== 583

+

+MD

+== 498

+

+MC

+== 492

+

+MN

+== 496

+

+ME

+== 499

+

+MS

+== 500

+

+MA

+== 504

+

+MZ

+== 508

+

+MM

+== 104

+

+NA

+== 516

+

+NR

+== 520

+

+NP

+== 524

+

+NL

+== 528

+

+NC

+== 540

+

+NZ

+== 554

+

+NI

+== 558

+

+NE

+== 562

+

+NG

+== 566

+

+NU

+== 570

+

+NF

+== 574

+

+MP

+== 580

+

+NO

+== 578

+

+OM

+== 512

+

+PK

+== 586

+

+PW

+== 585

+

+#PS

+#== 275

+

+PA

+== 591

+

+PG

+== 598

+

+PY

+== 600

+

+PE

+== 604

+

+PH

+== 608

+

+PN

+== 612

+

+PL

+== 616

+

+PT

+== 620

+

+PR

+== 630

+

+QA

+== 634

+

+RE

+== 638

+

+RO

+== 642

+

+RU

+== 643

+

+RW

+== 646

+

+BL

+== 652

+

+SH

+== 654

+

+KN

+== 659

+

+LC

+== 662

+

+MF

+== 663

+

+PM

+== 666

+

+VC

+== 670

+

+WS

+== 882

+

+SM

+== 674

+

+ST

+== 678

+

+SA

+== 682

+

+SN

+== 686

+

+RS

+== 688

+

+SC

+== 690

+

+SL

+== 694

+

+SG

+== 702

+

+SX

+== 534

+

+SK

+== 703

+

+SI

+== 705

+

+SB

+== 90

+

+SO

+== 706

+

+ZA

+== 710

+

+GS

+== 239

+

+ES

+== 724

+

+LK

+== 144

+

+SD

+== 736

+

+SR

+== 740

+

+#SJ

+#== 744

+

+SZ

+== 748

+

+SE

+== 752

+

+CH

+== 756

+

+SY

+== 760

+

+TW

+== 158

+

+TJ

+== 762

+

+TZ

+== 834

+

+TH

+== 764

+

+TL

+== 626

+

+TG

+== 768

+

+TK

+== 772

+

+TO

+== 776

+

+TT

+== 780

+

+TN

+== 788

+

+TR

+== 792

+

+TM

+== 795

+

+TC

+== 796

+

+TV

+== 798

+

+UG

+== 800

+

+UA

+== 804

+

+AE

+== 784

+

+GB

+== 826

+

+US

+== 840

+

+#UM

+#== 581

+

+UY

+== 858

+

+UZ

+== 860

+

+VU

+== 548

+

+VE

+== 862

+

+VN

+== 704

+

+VG

+== 92

+

+VI

+== 850

+

+WF

+== 876

+

+EH

+== 732

+

+YE

+== 887

+

+ZM

+== 894

+

+ZW

+== 716

diff --git a/data/editor/desert_main.rules b/data/editor/desert_main.rules
new file mode 100644
index 00000000..0102a197
--- /dev/null
+++ b/data/editor/desert_main.rules
@@ -0,0 +1,227 @@
+[Desert]
+Index 1
+BaseTile
+
+#random
+Index 2
+Pos 0 1 FULL
+Pos 0 -1 FULL
+Pos 1 0 FULL
+Pos -1 0 FULL
+Random 150
+
+Index 3
+Pos 0 1 FULL
+Pos 0 -1 FULL
+Pos 1 0 FULL
+Pos -1 0 FULL
+Random 150
+
+#top
+Index 16
+Pos 0 -1 EMPTY
+
+#right 
+Index 17
+Pos 1 0 EMPTY
+
+#bottom
+Index 18
+Pos 0 1 EMPTY
+
+#left
+Index 19
+Pos -1 0 EMPTY
+
+#corner top-right
+Index 33
+Pos 0 -1 EMPTY
+Pos 1 0 EMPTY
+
+#corner top-left
+Index 32
+Pos 0 -1 EMPTY
+Pos -1 0 EMPTY
+
+#corner bottom-left
+Index 35
+Pos 0 1 EMPTY
+Pos -1 0 EMPTY
+
+#corner bottom-right
+Index 34
+Pos 0 1 EMPTY
+Pos 1 0 EMPTY
+
+#inside corner top-right
+Index 51
+Pos -1 1 EMPTY
+Pos -1 0 FULL
+Pos 0 1 FULL
+
+#inside corner top-left
+Index 50
+Pos 1 1 EMPTY
+Pos 1 0 FULL
+Pos 0 1 FULL
+
+#inside corner bottom-left
+Index 49
+Pos 1 -1 EMPTY
+Pos 1 0 FULL
+Pos 0 -1 FULL
+
+#inside corner bottom-right
+Index 48
+Pos -1 -1 EMPTY
+Pos -1 0 FULL
+Pos 0 -1 FULL
+
+[Mine]
+Index 81
+BaseTile
+
+#random
+Index 82
+Pos 0 1 FULL
+Pos 0 -1 FULL
+Pos 1 0 FULL
+Pos -1 0 FULL
+Random 500
+
+Index 83
+Pos 0 1 FULL
+Pos 0 -1 FULL
+Pos 1 0 FULL
+Pos -1 0 FULL
+Random 500
+
+Index 84
+Pos 0 1 FULL
+Pos 0 -1 FULL
+Pos 1 0 FULL
+Pos -1 0 FULL
+Random 500
+
+Index 85
+Pos 0 1 FULL
+Pos 0 -1 FULL
+Pos 1 0 FULL
+Pos -1 0 FULL
+Random 500
+
+Index 86
+Pos 0 1 FULL
+Pos 0 -1 FULL
+Pos 1 0 FULL
+Pos -1 0 FULL
+Random 500
+
+Index 100
+Pos 0 1 FULL
+Pos 0 -1 FULL
+Pos 1 0 FULL
+Pos -1 0 FULL
+Random 500
+
+Index 101
+Pos 0 1 FULL
+Pos 0 -1 FULL
+Pos 1 0 FULL
+Pos -1 0 FULL
+Random 500
+
+Index 102
+Pos 0 1 FULL
+Pos 0 -1 FULL
+Pos 1 0 FULL
+Pos -1 0 FULL
+Random 500
+
+Index 117
+Pos 0 1 FULL
+Pos 0 -1 FULL
+Pos 1 0 FULL
+Pos -1 0 FULL
+Random 500
+
+Index 118
+Pos 0 1 FULL
+Pos 0 -1 FULL
+Pos 1 0 FULL
+Pos -1 0 FULL
+Random 500
+
+Index 133
+Pos 0 1 FULL
+Pos 0 -1 FULL
+Pos 1 0 FULL
+Pos -1 0 FULL
+Random 500
+
+Index 134
+Pos 0 1 FULL
+Pos 0 -1 FULL
+Pos 1 0 FULL
+Pos -1 0 FULL
+Random 500
+
+#top
+Index 96
+Pos 0 -1 EMPTY
+
+#right 
+Index 97
+Pos 1 0 EMPTY
+
+#bottom
+Index 98
+Pos 0 1 EMPTY
+
+#left
+Index 99
+Pos -1 0 EMPTY
+
+#corner top-right
+Index 113
+Pos 0 -1 EMPTY
+Pos 1 0 EMPTY
+
+#corner top-left
+Index 112
+Pos 0 -1 EMPTY
+Pos -1 0 EMPTY
+
+#corner bottom-left
+Index 115
+Pos 0 1 EMPTY
+Pos -1 0 EMPTY
+
+#corner bottom-right
+Index 114
+Pos 0 1 EMPTY
+Pos 1 0 EMPTY
+
+#inside corner top-right
+Index 131
+Pos -1 1 EMPTY
+Pos -1 0 FULL
+Pos 0 1 FULL
+
+#inside corner top-left
+Index 130
+Pos 1 1 EMPTY
+Pos 1 0 FULL
+Pos 0 1 FULL
+
+#inside corner bottom-left
+Index 129
+Pos 1 -1 EMPTY
+Pos 1 0 FULL
+Pos 0 -1 FULL
+
+#inside corner bottom-right
+Index 128
+Pos -1 -1 EMPTY
+Pos -1 0 FULL
+Pos 0 -1 FULL
diff --git a/data/editor/grass_main.rules b/data/editor/grass_main.rules
new file mode 100644
index 00000000..b909eb0e
--- /dev/null
+++ b/data/editor/grass_main.rules
@@ -0,0 +1,225 @@
+[Grass]
+Index 1
+BaseTile
+
+#random bones
+Index 2
+Pos 0 1 FULL
+Pos 0 -1 FULL
+Pos 1 0 FULL
+Pos -1 0 FULL
+Random 150
+
+Index 3
+Pos 0 1 FULL
+Pos 0 -1 FULL
+Pos 1 0 FULL
+Pos -1 0 FULL
+Random 150
+
+Index 66
+Pos 0 1 FULL
+Pos 0 -1 FULL
+Pos 1 0 FULL
+Pos -1 0 FULL
+Random 150
+
+Index 67
+Pos 0 1 FULL
+Pos 0 -1 FULL
+Pos 1 0 FULL
+Pos -1 0 FULL
+Random 150
+
+Index 68
+Pos 0 1 FULL
+Pos 0 -1 FULL
+Pos 1 0 FULL
+Pos -1 0 FULL
+Random 150
+#---------
+
+#top
+Index 16
+Pos 0 -1 EMPTY
+
+#right
+Index 21
+Pos 1 0 EMPTY
+
+#bottom
+Index 52
+Pos 0 1 EMPTY
+
+#left
+Index 20
+Pos -1 0 EMPTY
+
+#corner top-right
+Index 5
+Pos 0 -1 EMPTY
+Pos 1 0 EMPTY
+
+#corner top-left
+Index 4
+Pos 0 -1 EMPTY
+Pos -1 0 EMPTY
+
+#corner bottom-left
+Index 36
+Pos 0 1 EMPTY
+Pos -1 0 EMPTY
+
+#corner bottom-right
+Index 37
+Pos 0 1 EMPTY
+Pos 1 0 EMPTY
+
+#inside corner top-right
+Index 54
+Pos -1 1 EMPTY
+Pos -1 0 FULL
+Pos 0 1 FULL
+
+#inside corner top-left
+Index 53
+Pos 1 1 EMPTY
+Pos 1 0 FULL
+Pos 0 1 FULL
+
+#inside corner bottom-left
+Index 49
+Pos 1 -1 EMPTY
+Pos 1 0 FULL
+Pos 0 -1 FULL
+
+#inside corner bottom-right
+Index 48
+Pos -1 -1 EMPTY
+Pos -1 0 FULL
+Pos 0 -1 FULL
+
+#right bottom
+Index 22
+Pos -1 0 EMPTY
+Pos -1 1 FULL
+Pos 0 1 FULL
+
+#left bottom
+Index 38
+Pos 1 0 EMPTY
+Pos 1 1 FULL
+Pos 0 1 FULL
+
+#top corner right 2
+Index 33
+Pos 0 -1 EMPTY
+Pos 1 0 EMPTY
+Pos 1 1 FULL
+
+#top corner left 2
+Index 32
+Pos 0 -1 EMPTY
+Pos -1 0 EMPTY
+Pos -1 1 FULL
+
+[Cave]
+Index 13
+BaseTile
+
+#random bones
+Index 29
+Pos 0 1 FULL
+Pos 0 -1 FULL
+Pos 1 0 FULL
+Pos -1 0 FULL
+Random 150
+
+Index 42
+Pos 0 1 FULL
+Pos 0 -1 FULL
+Pos 1 0 FULL
+Pos -1 0 FULL
+Random 150
+
+Index 43
+Pos 0 1 FULL
+Pos 0 -1 FULL
+Pos 1 0 FULL
+Pos -1 0 FULL
+Random 150
+
+Index 44
+Pos 0 1 FULL
+Pos 0 -1 FULL
+Pos 1 0 FULL
+Pos -1 0 FULL
+Random 150
+
+Index 45
+Pos 0 1 FULL
+Pos 0 -1 FULL
+Pos 1 0 FULL
+Pos -1 0 FULL
+Random 150
+#---------
+
+#top
+Index 26
+Pos 0 -1 EMPTY
+
+#right
+Index 25
+Pos 1 0 EMPTY
+
+#bottom
+Index 10
+Pos 0 1 EMPTY
+
+#left
+Index 24
+Pos -1 0 EMPTY
+
+#corner top-right
+Index 9
+Pos 0 -1 EMPTY
+Pos 1 0 EMPTY
+
+#corner top-left
+Index 8
+Pos 0 -1 EMPTY
+Pos -1 0 EMPTY
+
+#corner bottom-left
+Index 40
+Pos 0 1 EMPTY
+Pos -1 0 EMPTY
+
+#corner bottom-right
+Index 41
+Pos 0 1 EMPTY
+Pos 1 0 EMPTY
+
+#inside corner top-right
+Index 12
+Pos -1 1 EMPTY
+Pos -1 0 FULL
+Pos 0 1 FULL
+
+#inside corner top-left
+Index 11
+Pos 1 1 EMPTY
+Pos 1 0 FULL
+Pos 0 1 FULL
+
+#inside corner bottom-left
+Index 27
+Pos 1 -1 EMPTY
+Pos 1 0 FULL
+Pos 0 -1 FULL
+
+#inside corner bottom-right
+Index 28
+Pos -1 -1 EMPTY
+Pos -1 0 FULL
+Pos 0 -1 FULL
diff --git a/data/editor/jungle_main.rules b/data/editor/jungle_main.rules
new file mode 100644
index 00000000..ada1f3ac
--- /dev/null
+++ b/data/editor/jungle_main.rules
@@ -0,0 +1,266 @@
+[Jungle]
+Index 1
+BaseTile
+
+#random bricks
+Index 66
+Pos 0 1 FULL
+Pos 0 -1 FULL
+Pos 1 0 FULL
+Pos -1 0 FULL
+Random 200
+
+Index 67
+Pos 0 1 FULL
+Pos 0 -1 FULL
+Pos 1 0 FULL
+Pos -1 0 FULL
+Random 200
+
+#top
+Index 16
+Pos 0 -1 EMPTY
+
+Index 96
+Pos 0 -1 EMPTY
+Random 15
+
+Index 97
+Pos 0 -1 EMPTY
+Random 15
+
+Index 98
+Pos 0 -1 EMPTY
+Random 15
+
+#right 
+Index 21
+Pos 1 0 EMPTY
+
+#bottom
+Index 52
+Pos 0 1 EMPTY
+
+Index 99
+Pos 0 1 EMPTY
+Random 10
+
+Index 100
+Pos 0 1 EMPTY
+Random 10
+
+Index 101
+Pos 0 1 EMPTY
+Random 10
+
+#left
+Index 21 XFLIP
+Pos -1 0 EMPTY
+
+#corner top-right
+Index 5
+Pos 0 -1 EMPTY
+Pos 1 0 EMPTY
+
+#corner top-left
+Index 5 XFLIP
+Pos 0 -1 EMPTY
+Pos -1 0 EMPTY
+
+#corner bottom-left
+Index 37 XFLIP
+Pos 0 1 EMPTY
+Pos -1 0 EMPTY
+
+Index 39 XFLIP
+Pos 0 1 EMPTY
+Pos -1 0 EMPTY
+Random 2
+
+#corner bottom-right
+Index 37
+Pos 0 1 EMPTY
+Pos 1 0 EMPTY
+
+Index 39
+Pos 0 1 EMPTY
+Pos 1 0 EMPTY
+Random 2
+
+#inside corner top-right
+Index 54
+Pos -1 1 EMPTY
+Pos -1 0 FULL
+Pos 0 1 FULL
+
+Index 53 XFLIP
+Pos -1 1 EMPTY
+Pos -1 0 FULL
+Pos 0 1 FULL
+Random 2
+
+#inside corner top-left
+Index 54 XFLIP
+Pos 1 1 EMPTY
+Pos 1 0 FULL
+Pos 0 1 FULL
+
+Index 53
+Pos 1 1 EMPTY
+Pos 1 0 FULL
+Pos 0 1 FULL
+Random 2
+
+#inside corner bottom-left
+Index 48 XFLIP
+Pos 1 -1 EMPTY
+Pos 1 0 FULL
+Pos 0 -1 FULL
+
+Index 49
+Pos 1 -1 EMPTY
+Pos 1 0 FULL
+Pos 0 -1 FULL
+Random 3
+
+Index 50 YFLIP
+Pos 1 -1 EMPTY
+Pos 1 0 FULL
+Pos 0 -1 FULL
+Random 3
+
+#inside corner bottom-right
+Index 48
+Pos -1 -1 EMPTY
+Pos -1 0 FULL
+Pos 0 -1 FULL
+
+Index 49 XFLIP
+Pos -1 -1 EMPTY
+Pos -1 0 FULL
+Pos 0 -1 FULL
+Random 3
+
+Index 51 YFLIP
+Pos -1 -1 EMPTY
+Pos -1 0 FULL
+Pos 0 -1 FULL
+Random 3
+
+#right bottom
+Index 22
+Pos -1 0 EMPTY
+Pos -1 1 FULL
+Pos 0 1 FULL
+
+#left bottom
+Index 22 XFLIP
+Pos 1 0 EMPTY
+Pos 1 1 FULL
+Pos 0 1 FULL
+
+#top corner right 2
+Index 33
+Pos 0 -1 EMPTY
+Pos 1 0 EMPTY
+Pos 1 1 FULL
+
+#top corner left 2
+Index 32
+Pos 0 -1 EMPTY
+Pos -1 0 EMPTY
+Pos -1 1 FULL
+
+[Jungle dark]
+Index 13
+BaseTile
+
+#random bricks
+Index 42
+Pos 0 1 FULL
+Pos 0 -1 FULL
+Pos 1 0 FULL
+Pos -1 0 FULL
+Random 150
+
+Index 43
+Pos 0 1 FULL
+Pos 0 -1 FULL
+Pos 1 0 FULL
+Pos -1 0 FULL
+Random 150
+
+Index 44
+Pos 0 1 FULL
+Pos 0 -1 FULL
+Pos 1 0 FULL
+Pos -1 0 FULL
+Random 150
+
+Index 45
+Pos 0 1 FULL
+Pos 0 -1 FULL
+Pos 1 0 FULL
+Pos -1 0 FULL
+Random 150
+#---------
+
+#top
+Index 26
+Pos 0 -1 EMPTY
+
+#right 
+Index 25
+Pos 1 0 EMPTY
+
+#bottom
+Index 10
+Pos 0 1 EMPTY
+
+#left
+Index 24
+Pos -1 0 EMPTY
+
+#corner top-right
+Index 9
+Pos 0 -1 EMPTY
+Pos 1 0 EMPTY
+
+#corner top-left
+Index 8
+Pos 0 -1 EMPTY
+Pos -1 0 EMPTY
+
+#corner bottom-left
+Index 40
+Pos 0 1 EMPTY
+Pos -1 0 EMPTY
+
+#corner bottom-right
+Index 41
+Pos 0 1 EMPTY
+Pos 1 0 EMPTY
+
+#inside corner top-right
+Index 12
+Pos -1 1 EMPTY
+Pos -1 0 FULL
+Pos 0 1 FULL
+
+#inside corner top-left
+Index 11
+Pos 1 1 EMPTY
+Pos 1 0 FULL
+Pos 0 1 FULL
+
+#inside corner bottom-left
+Index 27
+Pos 1 -1 EMPTY
+Pos 1 0 FULL
+Pos 0 -1 FULL
+
+#inside corner bottom-right
+Index 28
+Pos -1 -1 EMPTY
+Pos -1 0 FULL
+Pos 0 -1 FULL
diff --git a/data/editor/winter_main.rules b/data/editor/winter_main.rules
new file mode 100644
index 00000000..eaeaec8e
--- /dev/null
+++ b/data/editor/winter_main.rules
@@ -0,0 +1,177 @@
+[Winter]
+Index 1
+BaseTile
+
+#top
+Index 17
+Pos 0 -1 EMPTY
+
+Index 18
+Pos 0 -1 EMPTY
+Pos -1 0 INDEX 17
+
+Index 19
+Pos 0 -1 EMPTY
+Pos -1 0 INDEX 18
+
+#bottom
+Index 97
+Pos 0 1 EMPTY
+
+Index 98
+Pos 0 1 EMPTY
+Pos -1 0 INDEX 97
+
+Index 99
+Pos 0 1 EMPTY
+Pos -1 0 INDEX 98
+
+#right
+Index 2 XFLIP
+Pos 1 0 EMPTY
+
+#left
+Index 2
+Pos -1 0 EMPTY
+
+#corner top right
+Index 20
+Pos 0 -1 EMPTY
+Pos 1 0 EMPTY
+
+Index 24
+Pos 0 -1 EMPTY
+Pos 1 0 EMPTY
+Pos -1 0 INDEX 17
+
+#corner top left
+Index 16
+Pos 0 -1 EMPTY
+Pos -1 0 EMPTY
+
+#corner bottom right
+Index 100
+Pos 0 1 EMPTY
+Pos 1 0 EMPTY
+
+#corner bottom left
+Index 96
+Pos 0 1 EMPTY
+Pos -1 0 EMPTY
+
+#inside corner top right
+Index 8
+Pos 0 1 FULL
+Pos -1 0 FULL
+Pos -1 1 EMPTY
+
+#inside corner top left
+Index 7
+Pos 0 1 FULL
+Pos 1 0 FULL
+Pos 1 1 EMPTY
+
+#inside corner bottom right
+Index 4
+Pos 0 -1 FULL
+Pos -1 0 FULL
+Pos -1 -1 EMPTY
+
+#inside corner bottom left
+Index 3
+Pos 0 -1 FULL
+Pos 1 0 FULL
+Pos 1 -1 EMPTY
+
+#one tile height
+Index 113
+Pos 0 1 EMPTY
+Pos 0 -1 EMPTY
+
+Index 114
+Pos 0 1 EMPTY
+Pos 0 -1 EMPTY
+Pos -1 0 INDEX 113
+
+Index 115
+Pos 0 1 EMPTY
+Pos 0 -1 EMPTY
+Pos -1 0 INDEX 114
+
+#one tile height right
+Index 116
+Pos 0 1 EMPTY
+Pos 0 -1 EMPTY
+Pos 1 0 EMPTY
+
+Index 120
+Pos 0 1 EMPTY
+Pos 0 -1 EMPTY
+Pos 1 0 EMPTY
+Pos -1 0 INDEX 113
+
+#one tile height left
+Index 112
+Pos 0 1 EMPTY
+Pos 0 -1 EMPTY
+Pos -1 0 EMPTY
+
+#one tile height link right
+Index 6
+Pos -1 -1 EMPTY
+Pos -1 0 FULL
+Pos 0 -1 FULL
+Pos -1 1 EMPTY
+
+#one tile height link left
+Index 5
+Pos 1 -1 EMPTY
+Pos 1 0 FULL
+Pos 0 -1 FULL
+Pos 1 1 EMPTY
+
+[Winter dark]
+Index 177
+BaseTile
+
+#bottom
+Index 194
+Pos 0 1 EMPTY
+
+Index 195
+Pos 0 1 EMPTY
+Pos -1 0 INDEX 194
+
+Index 196
+Pos 0 1 EMPTY
+Pos -1 0 INDEX 195
+
+#right
+Index 178 XFLIP
+Pos 1 0 EMPTY
+
+#left
+Index 178
+Pos -1 0 EMPTY
+
+#corner bottom right
+Index 197
+Pos 0 1 EMPTY
+Pos 1 0 EMPTY
+
+#corner bottom left
+Index 193
+Pos 0 1 EMPTY
+Pos -1 0 EMPTY
+
+#inside corner top right
+Index 180
+Pos 0 1 FULL
+Pos -1 0 FULL
+Pos -1 1 EMPTY
+
+#inside corner top left
+Index 179
+Pos 0 1 FULL
+Pos 1 0 FULL
+Pos 1 1 EMPTY
diff --git a/data/languages/belarusian.txt b/data/languages/belarusian.txt
new file mode 100644
index 00000000..672995c0
--- /dev/null
+++ b/data/languages/belarusian.txt
@@ -0,0 +1,679 @@
+
+##### translated strings #####
+
+%d Bytes
+== %d байт
+
+%d of %d servers, %d players
+== %d з %d сервераў, %d гульцоў
+
+%d%% loaded
+== %d%% загружана
+
+%ds left
+== засталося %d сек.
+
+%i minute left
+== Засталася %i хвіліна!
+
+%i minutes left
+== Засталося %i хвілін!
+
+%i second left
+== Засталася %i секунда!
+
+%i seconds left
+== Засталося %i секунд!
+
+%s wins!
+== %s перамог!
+
+-Page %d-
+== -Старонка %d-
+
+Abort
+== Адмена
+
+Add
+== Дадаць
+
+Add Friend
+== Дадаць сябра
+
+Address
+== Адрас
+
+All
+== Усё
+
+Alpha
+== Празрыст.
+
+Always show name plates
+== Заўсёды паказваць нікі гульцоў
+
+Are you sure that you want to delete the demo?
+== Вы ўпэўнены, што жадаеце выдаліць дэма?
+
+Are you sure that you want to quit?
+== Вы сапраўды жадаеце выйсці?
+
+Are you sure that you want to remove the player from your friends list?
+== Вы ўпэўнены, што жадаеце выдаліць гульца з сяброў?
+
+As this is the first time you launch the game, please enter your nick name below. It's recommended that you check the settings to adjust them to your liking before joining a server.
+== Бо гэта ваш першы запуск гульні, калі ласка, увядзіце свой нік у поле ніжэй. Таксама рекоммендуется праверыць налады гульні і памяняць некаторыя з іх перад тым, як пачаць гуляць.
+
+Automatically record demos
+== Аўтаматычна запісваць дэма
+
+Automatically take game over screenshot
+== Рабіць здымак вынікаў гульні
+
+Blue team
+== Сінія
+
+Blue team wins!
+== Сінія перамаглі!
+
+Body
+== Цела
+
+Call vote
+== Галасаваць
+
+Change settings
+== Змяніць налады
+
+Chat
+== Чат
+
+Clan
+== Клан
+
+Client
+== Кліент
+
+Close
+== Выйсці
+
+Compatible version
+== Сумяшчальная версія
+
+Connect
+== Падлучыцца
+
+Connecting to
+== Падлучэнне да
+
+Connection Problems...
+== Праблемы з сувяззю...
+
+Console
+== Кансоль
+
+Controls
+== Кіраванне
+
+Count players only
+== Лічыць толькі гульцоў
+
+Country
+== Сцяг вашай краіны
+
+Crc:
+== Crc:
+
+Created:
+== Створаны:
+
+Current
+== Бягучы
+
+Current version: %s
+== Бягучая версія: %s
+
+Custom colors
+== Свае колеры
+
+Delete
+== Выдаліць
+
+Delete demo
+== Выдаліць дэма
+
+Demo details
+== Дэталі дэма
+
+Demofile: %s
+== Дэма: %s
+
+Demos
+== Дэма
+
+Disconnect
+== Адключыць
+
+Disconnected
+== Адключана
+
+Display Modes
+== Дазвол экрана
+
+Downloading map
+== Спампоўка карты
+
+Draw!
+== Нічыя!
+
+Dynamic Camera
+== Дынамічная камера
+
+Emoticon
+== Эмоцыі
+
+Enter
+== Уваход
+
+Error
+== Памылка
+
+Error loading demo
+== памылка пры загрузцы дэма
+
+FSAA samples
+== Сэмплаў FSAA
+
+Favorite
+== Абраны
+
+Favorites
+== Абраныя
+
+Feet
+== Ногі
+
+Filter
+== Фільтр
+
+Fire
+== Стрэл
+
+Folder
+== Тэчка
+
+Force vote
+== Фарсіраваць
+
+Free-View
+== Вольны агляд
+
+Friends
+== Сябры
+
+Fullscreen
+== Поўнаэкранны рэжым
+
+Game
+== Гульня
+
+Game info
+== Інфа пра гульню
+
+Game over
+== Гульня скончана
+
+Game type
+== Тып гульні
+
+Game types:
+== Тып гульні:
+
+General
+== Асноўныя
+
+Graphics
+== Графіка
+
+Grenade
+== Гранатамёт
+
+Hammer
+== Молат
+
+Has people playing
+== Не пусты сервер
+
+High Detail
+== Высокая дэталізацыя
+
+Hook
+== Крук
+
+Host address
+== Адрас сервера
+
+Hue
+== Адценне
+
+Info
+== Інфа
+
+Internet
+== Інтэрнэт
+
+Invalid Demo
+== Недапушчальнае дэма
+
+Join blue
+== За сініх
+
+Join game
+== Гуляць
+
+Join red
+== За чырвоных
+
+Jump
+== Скачок
+
+Kick player
+== Забаніць гульца
+
+LAN
+== LAN
+
+Language
+== Мова
+
+Length:
+== Даўжыня
+
+Lht.
+== Яркасць
+
+Loading
+== Загрузка
+
+MOTD
+== MOTD
+
+Map
+== Карта
+
+Map:
+== Карта:
+
+Max Screenshots
+== Максімальная колькасць здымкаў
+
+Max demos
+== Максімальная колькасць дэма
+
+Maximum ping:
+== Макс. пінг:
+
+Miscellaneous
+== Дадаткова
+
+Mouse sens.
+== Адчув. мышы
+
+Move left
+== Крок налева
+
+Move player to spectators
+== Зрабіць назіральнікам
+
+Move right
+== Крок направа
+
+Movement
+== Перасоўванне
+
+Mute when not active
+== Глушыць гукі, калі гульня неактыўная
+
+Name
+== Імя
+
+Name plates size
+== Памер
+
+Netversion:
+== Версія:
+
+New name:
+== Новае імя
+
+News
+== Навіны
+
+Next weapon
+== След. зброя
+
+Nickname
+== Нік
+
+No
+== Не
+
+No password
+== Без пароля
+
+No servers found
+== Сервера не знойдзены
+
+No servers match your filter criteria
+== Няма сервераў, падыходных пад ваш фільтр
+
+Ok
+== ОК
+
+Open
+== Адкрыць
+
+Parent Folder
+== Бацькоўскі каталог
+
+Password
+== Пароль
+
+Password incorrect
+== Пароль
+
+Ping
+== Пінг
+
+Pistol
+== Пісталет
+
+Play
+== Прагляд
+
+Play background music
+== Гуляць фонавую музыку
+
+Player
+== Гулец
+
+Player country:
+== Краіна:
+
+Player options
+== Опцыі гульца
+
+Players
+== Гульцы
+
+Please balance teams!
+== Збалансуйце каманды!
+
+Prev. weapon
+== Прад. зброя
+
+Quality Textures
+== Якасныя тэкстуры
+
+Quick search:
+== Хуткі пошук:
+
+Quit
+== Выйсце
+
+Quit anyway?
+== Выйсці?
+
+REC %3d:%02d
+== REC %3d:%02d
+
+Reason:
+== Чыннік:
+
+Record demo
+== Запісаць дэма
+
+Red team
+== Чырвоныя
+
+Red team wins!
+== Чырвоныя перамаглі!
+
+Refresh
+== Абнавіць
+
+Refreshing master servers
+== Абнаўленне спісу майстар-сервераў
+
+Remote console
+== Кансоль сервера
+
+Remove
+== Выдаліць
+
+Remove friend
+== Выдаліць сябра
+
+Rename
+== Пераназв.
+
+Rename demo
+== Пераназваць дэма
+
+Reset filter
+== Скінуць фільтры
+
+Reset to defaults
+== Скінуць налады
+
+Rifle
+== Бласцер
+
+Round
+== Раўнд
+
+Sample rate
+== Чашчыня
+
+Sat.
+== Кантраст
+
+Score
+== Ачкі
+
+Score board
+== Табло
+
+Score limit
+== Ліміт ачкоў
+
+Scoreboard
+== Табло
+
+Screenshot
+== Здымак
+
+Server address:
+== Адрас сервера
+
+Server details
+== Дэталі сервера
+
+Server filter
+== Фільтр сервераў
+
+Server info
+== Інфармацыя
+
+Server not full
+== Сервер не запоўнены
+
+Settings
+== Налады
+
+Shotgun
+== Драбавік
+
+Show chat
+== Паказаць чат
+
+Show friends only
+== Толькі з сябрамі
+
+Show ingame HUD
+== Паказваць нутрагульнявы HUD
+
+Show name plates
+== Паказваць нікі гульцоў
+
+Show only supported
+== Паказваць толькі падтрымоўваныя дазволы экрана
+
+Size:
+== Памер:
+
+Skins
+== Скіны
+
+Sound
+== Гук
+
+Sound error
+== Гукавая памылка
+
+Sound volume
+== Гучнасць
+
+Spectate
+== Назіраць
+
+Spectate next
+== Назіраць наст.
+
+Spectate previous
+== Назіраць папяр.
+
+Spectator mode
+== Назіральнік
+
+Spectators
+== Назіральнікі
+
+Standard gametype
+== Стандартны тып гульні
+
+Standard map
+== Стандартная карта
+
+Stop record
+== Стоп
+
+Strict gametype filter
+== Строгі фільтр рэжым.
+
+Sudden Death
+== Хуткая смерць
+
+Switch weapon on pickup
+== Перамыкаць зброю пры падборы
+
+Team
+== Каманда
+
+Team chat
+== Камандны чат
+
+Teeworlds %s is out! Download it at www.teeworlds.com!
+== Выйшла Teeworlds %s! Спампоўвайце на www.teeworlds.com!
+
+Texture Compression
+== Сціск тэкстур
+
+The audio device couldn't be initialised.
+== Аўдыё прылада не можа быць ініцыялізавана
+
+The server is running a non-standard tuning on a pure game type.
+== Сервер запушчаны з нестандартнымі наладамі на стандартным тыпе гульні.
+
+There's an unsaved map in the editor, you might want to save it before you quit the game.
+== Ёсць незахаваная карта ў рэдактары, Вы можаце захаваць яе перад тым, як выйсці.
+
+Time limit
+== Ліміт часу
+
+Time limit: %d min
+== Ліміт часу: %d
+
+Try again
+== ОК
+
+Type
+== Тып
+
+Type:
+== Тып:
+
+UI Color
+== Колер інтэрфейсу
+
+Unable to delete the demo
+== Немагчыма выдаліць дэма
+
+Unable to rename the demo
+== Немагчыма пераназваць дэма
+
+Use sounds
+== Выкарыстоўваць гукі
+
+Use team colors for name plates
+== Камандныя колеры для нікаў гульцоў
+
+V-Sync
+== Вертыкальная сінхранізацыя
+
+Version
+== Версія
+
+Version:
+== Версія:
+
+Vote command:
+== Камманда галасавання:
+
+Vote description:
+== Апісанне галасавання:
+
+Vote no
+== Супраць
+
+Vote yes
+== За
+
+Voting
+== Галасаванне
+
+Warmup
+== Размінка
+
+Weapon
+== Зброя
+
+Welcome to Teeworlds
+== Сардэчна запрашаем у Teeworlds!
+
+Yes
+== Так
+
+You must restart the game for all settings to take effect.
+== Перазапусціце гульню для ўжывання змен.
+
+Your skin
+== Ваш скін
+
+no limit
+== Без ліміту
+
+##### needs translation #####
+
+##### old translations #####
+
diff --git a/data/languages/bosnian.txt b/data/languages/bosnian.txt
index d5c9ccd8..4888db6a 100644
--- a/data/languages/bosnian.txt
+++ b/data/languages/bosnian.txt
@@ -145,6 +145,9 @@ Delete demo
 Demo details
 == Podaci o demo-snimku
 
+Demofile: %s
+== Demo-snimak: %s
+
 Demos
 == Demo
 
@@ -388,9 +391,15 @@ Pistol
 Play
 == Pogledaj
 
+Play background music
+== Pozadinska muzika
+
 Player
 == Igrač
 
+Player country:
+== Država
+
 Player options
 == Postavke igrača
 
@@ -538,6 +547,12 @@ Sound volume
 Spectate
 == Posmatraj
 
+Spectate next
+== Posmatraj narednog
+
+Spectate previous
+== Posmatraj prethodnog
+
 Spectator mode
 == Posmatrački mod
 
@@ -553,6 +568,9 @@ Standard map
 Stop record
 == Prekini snimanje
 
+Strict gametype filter
+== Striktan filter tipa igre
+
 Sudden Death
 == Iznenadna smrt
 
@@ -657,23 +675,5 @@ no limit
 
 ##### needs translation #####
 
-Demofile: %s
-== 
-
-Play background music
-== 
-
-Player country:
-== 
-
-Spectate next
-== 
-
-Spectate previous
-== 
-
-Strict gametype filter
-== 
-
 ##### old translations #####
 
diff --git a/data/languages/brazilian_portuguese.txt b/data/languages/brazilian_portuguese.txt
new file mode 100644
index 00000000..a83a0d05
--- /dev/null
+++ b/data/languages/brazilian_portuguese.txt
@@ -0,0 +1,679 @@
+
+##### translated strings #####
+
+%d Bytes
+== %d Bytes
+
+%d of %d servers, %d players
+== %d de %d servidores, %d jogadores
+
+%d%% loaded
+== %d%% carregado
+
+%ds left
+== Faltam %ds
+
+%i minute left
+== Falta %i minuto
+
+%i minutes left
+== Faltam %i minutos
+
+%i second left
+== Falta %i segundo
+
+%i seconds left
+== Faltam %i segundos
+
+%s wins!
+== %s vence!
+
+-Page %d-
+== -Página %d-
+
+Abort
+== Cancelar
+
+Add
+== Adicionar
+
+Add Friend
+== Adicionar amigo
+
+Address
+== Endereço
+
+All
+== Todos
+
+Alpha
+== Alpha
+
+Always show name plates
+== Sempre mostrar apelidos
+
+Are you sure that you want to delete the demo?
+== Tem certeza que deseja deletar o demo?
+
+Are you sure that you want to quit?
+== Você tem certeza que deseja sair?
+
+Are you sure that you want to remove the player from your friends list?
+== Tem certeza que deseja remover o jogador de sua lista de amigos?
+
+As this is the first time you launch the game, please enter your nick name below. It's recommended that you check the settings to adjust them to your liking before joining a server.
+== Como esta é a primeira vez que você abre o jogo, por favor, coloque seu apelido abaixo. É recomendado que você verifique as configurações e então ajuste-as para suas preferências antes de entrar em um servidor.
+
+Automatically record demos
+== Gravar demos automaticamente
+
+Automatically take game over screenshot
+== Capturar tela final de jogo automaticamente
+
+Blue team
+== Time azul
+
+Blue team wins!
+== Vitória do time azul!
+
+Body
+== Corpo
+
+Call vote
+== Votar
+
+Change settings
+== Mudar configurações
+
+Chat
+== Chat
+
+Clan
+== Clã
+
+Client
+== Cliente
+
+Close
+== Fechar
+
+Compatible version
+== Versão compatível
+
+Connect
+== Conectar
+
+Connecting to
+== Conectando a
+
+Connection Problems...
+== Problemas de conexão...
+
+Console
+== Console
+
+Controls
+== Controles
+
+Count players only
+== Contar apenas jogadores
+
+Country
+== País
+
+Crc:
+== Crc:
+
+Created:
+== Criado:
+
+Current
+== Atual
+
+Current version: %s
+== Versão atual: %s
+
+Custom colors
+== Cores personalizadas
+
+Delete
+== Deletar
+
+Delete demo
+== Deletar demo
+
+Demo details
+== Detalhes do demo
+
+Demofile: %s
+== Demo: %s
+
+Demos
+== Demos
+
+Disconnect
+== Desconectar
+
+Disconnected
+== Desconectado
+
+Display Modes
+== Modos de exibição
+
+Downloading map
+== Baixando mapa
+
+Draw!
+== Empate!
+
+Dynamic Camera
+== Câmera dinâmica
+
+Emoticon
+== Emoticon
+
+Enter
+== Entrar
+
+Error
+== Erro
+
+Error loading demo
+== Erro ao carregar demo
+
+FSAA samples
+== Amostras FSAA
+
+Favorite
+== Favorito
+
+Favorites
+== Favoritos
+
+Feet
+== Pés
+
+Filter
+== Filtro
+
+Fire
+== Atirar
+
+Folder
+== Pasta
+
+Force vote
+== Forçar votação
+
+Free-View
+== Visualização livre
+
+Friends
+== Amigos
+
+Fullscreen
+== Tela cheia
+
+Game
+== Jogo
+
+Game info
+== Jogo
+
+Game over
+== Fim do jogo
+
+Game type
+== Tipo de jogo
+
+Game types:
+== Tipos de jogo:
+
+General
+== Geral
+
+Graphics
+== Gráficos
+
+Grenade
+== Granada
+
+Hammer
+== Martelo
+
+Has people playing
+== Há pessoas jogando
+
+High Detail
+== Mostrar detalhes
+
+Hook
+== Gancho
+
+Host address
+== Endereço do servidor
+
+Hue
+== Matiz
+
+Info
+== Informações
+
+Internet
+== Internet
+
+Invalid Demo
+== Demo inválido
+
+Join blue
+== Azul
+
+Join game
+== Entrar no jogo
+
+Join red
+== Vermelho
+
+Jump
+== Pular
+
+Kick player
+== Expulsar jogador
+
+LAN
+== LAN
+
+Language
+== Idioma
+
+Length:
+== Duração:
+
+Lht.
+== Luminos.
+
+Loading
+== Carregando
+
+MOTD
+== MOTD
+
+Map
+== Mapa
+
+Map:
+== Mapa:
+
+Max Screenshots
+== Máximo de capturas de tela
+
+Max demos
+== Máximo de demos
+
+Maximum ping:
+== Ping máximo:
+
+Miscellaneous
+== Diversos
+
+Mouse sens.
+== Sens. do mouse
+
+Move left
+== Esquerda
+
+Move player to spectators
+== Mover jogador para espectadores
+
+Move right
+== Direita
+
+Movement
+== Movimento
+
+Mute when not active
+== Silenciar quando inativo
+
+Name
+== Nome
+
+Name plates size
+== Tamanho dos apelidos
+
+Netversion:
+== Netversion
+
+New name:
+== Novo nome:
+
+News
+== Novidades
+
+Next weapon
+== Próxima arma
+
+Nickname
+== Apelido
+
+No
+== Não
+
+No password
+== Sem senha
+
+No servers found
+== Nenhum servidor encontrado
+
+No servers match your filter criteria
+== Nenhum servidor corresponde aos critérios do filtro
+
+Ok
+== Ok
+
+Open
+== Abrir
+
+Parent Folder
+== Diretório pai
+
+Password
+== Senha
+
+Password incorrect
+== Senha incorreta
+
+Ping
+== Ping
+
+Pistol
+== Pistola
+
+Play
+== Assistir
+
+Play background music
+== Tocar música de fundo
+
+Player
+== Jogador
+
+Player country:
+== País do jogador:
+
+Player options
+== Opções do jogador
+
+Players
+== Jogadores
+
+Please balance teams!
+== Favor balancear os times!
+
+Prev. weapon
+== Arma anterior
+
+Quality Textures
+== Texturas de qualidade
+
+Quick search:
+== Pesquisa rápida:
+
+Quit
+== Sair
+
+Quit anyway?
+== Sair mesmo assim?
+
+REC %3d:%02d
+== REC %3d:%02d
+
+Reason:
+== Motivo:
+
+Record demo
+== Gravar demo
+
+Red team
+== Time vermelho
+
+Red team wins!
+== Vitória do time vermelho!
+
+Refresh
+== Atualizar
+
+Refreshing master servers
+== Atualizando servidores mestres
+
+Remote console
+== Console remoto
+
+Remove
+== Deletar
+
+Remove friend
+== Deletar amigo
+
+Rename
+== Renomear
+
+Rename demo
+== Renomear demo
+
+Reset filter
+== Resetar filtro
+
+Reset to defaults
+== Resetar configurações
+
+Rifle
+== Laser
+
+Round
+== Rodada
+
+Sample rate
+== Frequência do som
+
+Sat.
+== Saturação
+
+Score
+== Pontos
+
+Score board
+== Placar
+
+Score limit
+== Pontuação máx.
+
+Scoreboard
+== Placar
+
+Screenshot
+== Capturar tela
+
+Server address:
+== Endereço:
+
+Server details
+== Detalhes do servidor
+
+Server filter
+== Filtro de servidores
+
+Server info
+== Servidor
+
+Server not full
+== Servidor não lotado
+
+Settings
+== Configurações
+
+Shotgun
+== Espingarda
+
+Show chat
+== Mostrar chat
+
+Show friends only
+== Mostrar apenas amigos
+
+Show ingame HUD
+== Mostrar HUD do jogo
+
+Show name plates
+== Mostrar apelidos
+
+Show only supported
+== Mostrar apenas modos suportados
+
+Size:
+== Tamanho:
+
+Skins
+== Skins
+
+Sound
+== Som
+
+Sound error
+== Erro de som
+
+Sound volume
+== Volume do som
+
+Spectate
+== Observar
+
+Spectate next
+== Observar próximo
+
+Spectate previous
+== Observar anterior
+
+Spectator mode
+== Modo espectador
+
+Spectators
+== Espectadores
+
+Standard gametype
+== Tipo de jogo padrão
+
+Standard map
+== Mapa padrão
+
+Stop record
+== Parar a gravação
+
+Strict gametype filter
+== Filtrar tipo de jogo exato
+
+Sudden Death
+== Morte Súbita
+
+Switch weapon on pickup
+== Equipar arma ao pegá-la
+
+Team
+== Time
+
+Team chat
+== Chat do time
+
+Teeworlds %s is out! Download it at www.teeworlds.com!
+== Teeworlds %s foi lançado! Baixe-o em www.teeworlds.com!
+
+Texture Compression
+== Compressão de textura
+
+The audio device couldn't be initialised.
+== O dispositivo de áudio não pôde ser inicializado.
+
+The server is running a non-standard tuning on a pure game type.
+== O servidor está rodando com modificações em um tipo de jogo oficial.
+
+There's an unsaved map in the editor, you might want to save it before you quit the game.
+== Existe um mapa não salvo no editor, você pode querer salvá-lo antes de sair do jogo.
+
+Time limit
+== Limite de tempo
+
+Time limit: %d min
+== Limite de tempo: %d minutos
+
+Try again
+== Tente de novo
+
+Type
+== Tipo
+
+Type:
+== Tipo:
+
+UI Color
+== Cor do menu
+
+Unable to delete the demo
+== Não foi possível deletar o demo
+
+Unable to rename the demo
+== Não foi possível renomear o demo
+
+Use sounds
+== Usar sons
+
+Use team colors for name plates
+== Usar cores dos times em apelidos
+
+V-Sync
+== V-Sync
+
+Version
+== Versão
+
+Version:
+== Versão
+
+Vote command:
+== Comando da votação:
+
+Vote description:
+== Descrição da votação:
+
+Vote no
+== Votar Não
+
+Vote yes
+== Votar Sim
+
+Voting
+== Votação
+
+Warmup
+== Aquecimento
+
+Weapon
+== Arma
+
+Welcome to Teeworlds
+== Bem-vindo ao Teeworlds!
+
+Yes
+== Sim
+
+You must restart the game for all settings to take effect.
+== Você deve reiniciar o jogo para que todas as alterações tenham efeito.
+
+Your skin
+== Sua skin
+
+no limit
+== sem limite
+
+##### needs translation #####
+
+##### old translations #####
+
diff --git a/data/languages/bulgarian.txt b/data/languages/bulgarian.txt
index 80b043a3..38df7891 100644
--- a/data/languages/bulgarian.txt
+++ b/data/languages/bulgarian.txt
@@ -53,16 +53,16 @@ Always show name plates
 == Винаги показвай лентите с имената
 
 Are you sure that you want to delete the demo?
-== Сигурни ли сте че искате да изтриете това демо?
+== Сигуен ли си че искаш да изтриеш това демо?
 
 Are you sure that you want to quit?
-== Сигурни ли сте че искате да напуснете?
+== Сигурен ли си че искаш да напуснеш?
 
 Are you sure that you want to remove the player from your friends list?
-== Сигурни ли сте че искате да премахнете този играч от листа с приятели?
+== Сигурен ли си че искаш да премахнеш този играч от листа с приятели?
 
 As this is the first time you launch the game, please enter your nick name below. It's recommended that you check the settings to adjust them to your liking before joining a server.
-== Тъй като стартирате играта за първи път, моля да въведете вашият ник отдолу. Препоръчително е да проверите и нагласите настройките по ваш избор преди да започнете игра.
+== Тъй като стартираш играта за първи път, моля въведи своя ник отдолу. Препоръчително е да провериш и нагласиш настройките по ваш свой избор преди да започнеш игра.
 
 Automatically record demos
 == Записвай демота автоматично
@@ -145,6 +145,9 @@ Delete demo
 Demo details
 == Детайли за демото
 
+Demofile: %s
+== Демофайл: %s
+
 Demos
 == Демота
 
@@ -347,7 +350,7 @@ News
 == Новини
 
 Next weapon
-== Следващо оръжие
+== След. оръжие
 
 Nickname
 == Ник
@@ -362,7 +365,7 @@ No servers found
 == Няма намерени сървъри
 
 No servers match your filter criteria
-== Няма сървъри съответстващи вашите настройки
+== Няма сървъри съответстващи твоите настройки
 
 Ok
 == Добре
@@ -388,9 +391,15 @@ Pistol
 Play
 == Възпроизведи
 
+Play background music
+== Пусни музика за фон
+
 Player
 == Играч
 
+Player country:
+== Страна на играча:
+
 Player options
 == Настройки на Играча
 
@@ -536,7 +545,10 @@ Sound volume
 == Сила на звука
 
 Spectate
-== Наблюдавайте
+== Наблюдавай
+
+Spectate next
+== Наблюдавай след.
 
 Spectator mode
 == Наблюдател
@@ -553,6 +565,9 @@ Standard map
 Stop record
 == Спри записа
 
+Strict gametype filter
+== Стриктен геймтайп филтър
+
 Sudden Death
 == Внезапна Смърт
 
@@ -566,13 +581,13 @@ Team chat
 == Отборен чат
 
 Teeworlds %s is out! Download it at www.teeworlds.com!
-== Излезна Teeworlds %s! Свалете новата версия от www.teeworlds.com!
+== Излезна Teeworlds %s! Свали новата версия от www.teeworlds.com!
 
 Texture Compression
 == Компресиране на Текстурите
 
 The audio device couldn't be initialised.
-== Аудио устройството не може да бъде стартирано
+== Аудио устройството не може да бъде стартирано.
 
 The server is running a non-standard tuning on a pure game type.
 == Този сървър използва нестандартен тунинг на стандартен тип ига.
@@ -587,7 +602,7 @@ Time limit: %d min
 == Лимит на Времето: %d мин
 
 Try again
-== Опитайте Отново
+== Опитай пак
 
 Type
 == Тип
@@ -620,10 +635,10 @@ Version:
 == Версия:
 
 Vote command:
-== Гласувай за команда:
+== Вот команда:
 
 Vote description:
-== Гласувай за обяснение:
+== Вот дефиниция:
 
 Vote no
 == Против
@@ -647,33 +662,18 @@ Yes
 == Да
 
 You must restart the game for all settings to take effect.
-== Трябва да рестартирате играта за да поемат ефект новите настройки.
+== Трябва да рестартираш играта за да поемат ефект новите настройки.
 
 Your skin
-== Вашият модел
+== Твоят модел
 
 no limit
 == Без лимит
 
 ##### needs translation #####
 
-Demofile: %s
-== 
-
-Play background music
-== 
-
-Player country:
-== 
-
-Spectate next
-== 
-
 Spectate previous
 == 
 
-Strict gametype filter
-== 
-
 ##### old translations #####
 
diff --git a/data/languages/czech.txt b/data/languages/czech.txt
index 7f26b274..5d50f47a 100644
--- a/data/languages/czech.txt
+++ b/data/languages/czech.txt
@@ -1,3 +1,4 @@
+
 ##### translated strings #####
 
 %d Bytes
@@ -25,7 +26,7 @@
 == Zbývá sekund: %i
 
 %s wins!
-== %s zvítězil!
+== Vítězí %s!
 
 -Page %d-
 == -Strana %d-
@@ -397,7 +398,7 @@ Player
 == Hráč
 
 Player country:
-== Národnost hráče:
+== Národnost:
 
 Player options
 == Nastavení hráčů
@@ -550,7 +551,7 @@ Spectate next
 == Pozorovat dalšího
 
 Spectate previous
-== Pozorovat předchozího
+== Pozorovat minulého
 
 Spectator mode
 == Nastavit pozorování
@@ -583,7 +584,7 @@ Team chat
 == Týmový chat
 
 Teeworlds %s is out! Download it at www.teeworlds.com!
-== Vyšlo nové Teeworlds %s! Stáhněte si ji na www.teeworlds.com!
+== Stáhněte si nové Teeworlds %s na www.teeworlds.com!
 
 Texture Compression
 == Komprimované textury
diff --git a/data/languages/dutch.txt b/data/languages/dutch.txt
index 978ff608..4375f784 100644
--- a/data/languages/dutch.txt
+++ b/data/languages/dutch.txt
@@ -62,7 +62,7 @@ Are you sure that you want to remove the player from your friends list?
 == Weet je zeker dat je deze speler uit je vriendenlijst wilt verwijderen?
 
 As this is the first time you launch the game, please enter your nick name below. It's recommended that you check the settings to adjust them to your liking before joining a server.
-== Omdat dit de eerste keer is dat je het spel opstart, moet je een nicknaam kiezen. Doe dat hieronder. Het is aanbevolen om de instellingen te controleren, voordat je een spel start.
+== Omdat dit de eerste keer is dat je het spel opstart, moet je een bijnaam kiezen. Doe dat hieronder. Het is aanbevolen om de instellingen te controleren voordat je een spel start.
 
 Automatically record demos
 == Automatisch demo's opnemen
@@ -145,6 +145,9 @@ Delete demo
 Demo details
 == Demo details
 
+Demofile: %s
+== Demobestand: %s
+
 Demos
 == Demo's
 
@@ -350,7 +353,7 @@ Next weapon
 == Volgend wapen
 
 Nickname
-== Nicknaam
+== Bijnaam
 
 No
 == Nee
@@ -394,6 +397,9 @@ Play background music
 Player
 == Speler
 
+Player country:
+== Speler land:
+
 Player options
 == Speler opties
 
@@ -428,10 +434,10 @@ Record demo
 == Neem demo op
 
 Red team
-== Rood
+== Rode team
 
 Red team wins!
-== Rood wint!
+== Rode team wint!
 
 Refresh
 == Vernieuwen
@@ -562,6 +568,9 @@ Standard map
 Stop record
 == Stop met opnemen
 
+Strict gametype filter
+== Strikt speltype filter
+
 Sudden Death
 == Sudden Death
 
@@ -590,7 +599,7 @@ There's an unsaved map in the editor, you might want to save it before you quit
 == Er is een onopgeslagen kaart in de editor, misschien wil je deze opslaan voordat je stopt.
 
 Time limit
-== Tijdlimiet
+== Tijdslimiet
 
 Time limit: %d min
 == Tijdslimiet: %d minuten
@@ -666,14 +675,5 @@ no limit
 
 ##### needs translation #####
 
-Demofile: %s
-== 
-
-Player country:
-== 
-
-Strict gametype filter
-== 
-
 ##### old translations #####
 
diff --git a/data/languages/finnish.txt b/data/languages/finnish.txt
index 8aab046f..77ce6cf7 100644
--- a/data/languages/finnish.txt
+++ b/data/languages/finnish.txt
@@ -145,6 +145,9 @@ Delete demo
 Demo details
 == Demon tiedot
 
+Demofile: %s
+== Demotiedosto: %s
+
 Demos
 == Demot
 
@@ -388,9 +391,15 @@ Pistol
 Play
 == Toista
 
+Play background music
+== Soita taustamusiikki
+
 Player
 == Pelaaja
 
+Player country:
+== Pelaajan maa:
+
 Player options
 == Pelaajavalinnat
 
@@ -509,7 +518,7 @@ Show chat
 == Näytä chatti
 
 Show friends only
-== Näytä ystävät
+== Näytä vain ystävät
 
 Show ingame HUD
 == Näytä peli-HUD
@@ -538,6 +547,12 @@ Sound volume
 Spectate
 == Katso
 
+Spectate next
+== Katso seuraavaa
+
+Spectate previous
+== Katso edellistä
+
 Spectator mode
 == Katsojatila
 
@@ -553,6 +568,9 @@ Standard map
 Stop record
 == Lopeta nauhoit.
 
+Strict gametype filter
+== Tarkka pelityyppisuodin
+
 Sudden Death
 == Äkkikuolema
 
@@ -657,23 +675,5 @@ no limit
 
 ##### needs translation #####
 
-Demofile: %s
-== 
-
-Play background music
-== 
-
-Player country:
-== 
-
-Spectate next
-== 
-
-Spectate previous
-== 
-
-Strict gametype filter
-== 
-
 ##### old translations #####
 
diff --git a/data/languages/hungarian.txt b/data/languages/hungarian.txt
new file mode 100644
index 00000000..49f3116a
--- /dev/null
+++ b/data/languages/hungarian.txt
@@ -0,0 +1,679 @@
+
+##### translated strings #####
+
+%d Bytes
+== %d Bit
+
+%d of %d servers, %d players
+== %d Szerver, %d Játékos
+
+%d%% loaded
+== %d%% betöltve
+
+%ds left
+==  %ds vissza
+
+%i minute left
+== %i perc vissza
+
+%i minutes left
+== %i perc vissza
+
+%i second left
+== %i másodperc vissza
+
+%i seconds left
+== %i másodperc vissza
+
+%s wins!
+== %s nyert!
+
+-Page %d-
+== -oldal %d-
+
+Abort
+== Mégse
+
+Add
+== Hozzáad
+
+Add Friend
+== Hozzáad barátot
+
+Address
+== Cím
+
+All
+== Mindenki
+
+Alpha
+== Alpha
+
+Always show name plates
+== Mindig mutassa a névtáblát
+
+Are you sure that you want to delete the demo?
+== Biztos hogy le akarod törölni a demót?
+
+Are you sure that you want to quit?
+== Biztos hogy ki akarsz lépni?
+
+Are you sure that you want to remove the player from your friends list?
+== Biztos vagy benne hogy ki akarod törölni a játékost a barátok listájáról?
+
+As this is the first time you launch the game, please enter your nick name below. It's recommended that you check the settings to adjust them to your liking before joining a server.
+== Mivel ez az első alkalom hogy elindítottad ezt a játékot, kérlekk add meg a neved!
+
+Automatically record demos
+== Magától rögzítse a demókat
+
+Automatically take game over screenshot
+== Magától készítsen a játék végén képet
+
+Blue team
+== Kék csapat
+
+Blue team wins!
+== A kék csapat nyert!
+
+Body
+== Test
+
+Call vote
+== Szavazás
+
+Change settings
+== Beállítások átállítása
+
+Chat
+== Chat
+
+Clan
+== Klán
+
+Client
+== Kliens
+
+Close
+== Bezárás
+
+Compatible version
+== Kompatibilis Verzió
+
+Connect
+== Csatlakozás
+
+Connecting to
+== Csatlakozás a
+
+Connection Problems...
+== Csatlakozási problémák...
+
+Console
+== Konzol
+
+Controls
+== Irányítás
+
+Count players only
+== Csak számontartott játékosok
+
+Country
+== Ország
+
+Crc:
+== Crc:
+
+Created:
+== Készítette:
+
+Current
+== Aktuális
+
+Current version: %s
+== Aktuális verzió: %s
+
+Custom colors
+== Egyéni színek
+
+Delete
+== Törlés
+
+Delete demo
+== Demó törlése
+
+Demo details
+== Információk a demóról
+
+Demos
+== Demók
+
+Disconnect
+== Szerver elhagyása
+
+Disconnected
+== Kilépett
+
+Display Modes
+== Kijelző módok
+
+Downloading map
+== Pálya letöltése
+
+Draw!
+== Rajzolj!
+
+Dynamic Camera
+== Dinamikus kamera
+
+Emoticon
+== Hangulatjel
+
+Enter
+== Belépés
+
+Error
+== Hiba
+
+Error loading demo
+== Hiba a demó betöltésében
+
+FSAA samples
+== FSAA mintáku
+
+Favorite
+== Kedvenc
+
+Favorites
+== Kedvencek
+
+Feet
+== Láb
+
+Filter
+== Szűrő
+
+Fire
+== Tűz
+
+Folder
+== Mappa
+
+Force vote
+== Különleges szavazás
+
+Free-View
+== Szabad-nézet
+
+Friends
+== Barátok
+
+Fullscreen
+== Teljesképernyő
+
+Game
+== Játék
+
+Game info
+== Játék infó
+
+Game over
+== Játék vége
+
+Game type
+== Játék fajtája
+
+Game types:
+== Játék fajtái:
+
+General
+== Általános
+
+Graphics
+== Grafika
+
+Grenade
+== Gránát
+
+Hammer
+== Kalapács
+
+Has people playing
+== Játékos játszik
+
+High Detail
+== Jó részletek
+
+Hook
+== Horog
+
+Host address
+== Szerver címe
+
+Hue
+== Színárnyalat
+
+Info
+== Infó
+
+Internet
+== Internet
+
+Invalid Demo
+== Érvénytelen demó
+
+Join blue
+== Kékhez lépés
+
+Join game
+== Csatlakozás a játékhoz
+
+Join red
+== Piroshoz lépés
+
+Jump
+== Ugrás
+
+Kick player
+== Játékos kirúgása
+
+LAN
+== Helyi
+
+Language
+== Nyelv
+
+Length:
+== Hossza:
+
+Lht.
+== Lht.
+
+Loading
+== Betöltés
+
+MOTD
+== Napi üzenet
+
+Map
+== Pálya
+
+Map:
+== Pálya:
+
+Max Screenshots
+== Maximum Fotó
+
+Max demos
+== Maximum Demó
+
+Maximum ping:
+== Maximum Ping:
+
+Miscellaneous
+== Vegyes
+
+Mouse sens.
+== Egér érzékenysége
+
+Move left
+== Balra lépés
+
+Move player to spectators
+== Megfigyelő lett
+
+Move right
+== Jobbra lépés
+
+Movement
+== Mozgás
+
+Mute when not active
+== Letiltás ha nem aktív
+
+Name
+== Név
+
+Name plates size
+== Névtáblák mérete
+
+Netversion:
+== Netes verzió:
+
+New name:
+== Új Név:
+
+News
+== Hírek
+
+Next weapon
+== Következő fegyver
+
+Nickname
+== Becenév
+
+No
+== Nem
+
+No password
+== Jelszó nélküli
+
+No servers found
+== Nem talált szervereket
+
+No servers match your filter criteria
+== Nincs szerver a szűrőfeltételeidhez
+
+Ok
+== Oké
+
+Open
+== Megnyit
+
+Parent Folder
+== Szülői mappa
+
+Password
+== Jelszó
+
+Password incorrect
+== Helytelen jelszó
+
+Ping
+== Ping
+
+Pistol
+== Pisztoly
+
+Play
+== Játék
+
+Player
+== Játékos
+
+Player options
+== Játékos beállításai
+
+Players
+== Játékosok
+
+Please balance teams!
+== Kérlek egyenlítsd ki a csapatokat!
+
+Prev. weapon
+== Előző fegyver
+
+Quality Textures
+== Minőségi kidolgozás
+
+Quick search:
+== Gyors keresés:
+
+Quit
+== Kilépés
+
+Quit anyway?
+== Mindenképpen kilép?
+
+REC %3d:%02d
+== REC %3d:%02d
+
+Reason:
+== Indok:
+
+Record demo
+== Demó felvétele
+
+Red team
+== Piros csapat
+
+Red team wins!
+== A piros csapat nyert!
+
+Refresh
+== Újratöltés
+
+Refreshing master servers
+== A master szerverek frissítése
+
+Remote console
+== Távoli konzol
+
+Remove
+== Eltávolítás
+
+Remove friend
+== Barát eltávolítása
+
+Rename
+== Átnevezés
+
+Rename demo
+== Demó átnevezése
+
+Reset filter
+== Szűrő visszaállítása
+
+Reset to defaults
+== Visszaállítás az alapértelmezettre
+
+Rifle
+== Lézer
+
+Round
+== Menet
+
+Sample rate
+== Mintavételi frekvencia
+
+Sat.
+== Sat.
+
+Score
+== Pontszám
+
+Score board
+== Pontszám tábla
+
+Score limit
+== Ponthatár
+
+Scoreboard
+== Pontszámtábla
+
+Screenshot
+== Pillanatkép
+
+Server address:
+== Szerver címe:
+
+Server details
+== Szerver részletei
+
+Server filter
+== Szerver szűrő
+
+Server info
+== Szerver infó
+
+Server not full
+== Szerver nincs tele
+
+Settings
+== Beállítások
+
+Shotgun
+== Sörétes puska
+
+Show chat
+== Chat mutatása
+
+Show friends only
+== Barátok mutatása
+
+Show ingame HUD
+== Játék közbeni HUD mutatása
+
+Show name plates
+== Név táblák mutatása
+
+Show only supported
+== Csak támogatott mutatása
+
+Size:
+== Méret:
+
+Skins
+== Skinek
+
+Sound
+== Hang
+
+Sound error
+== Hang hiba
+
+Sound volume
+== Hangerő
+
+Spectate
+== Megfigyelés
+
+Spectator mode
+== Néző mód
+
+Spectators
+== Megfigyelők
+
+Standard gametype
+== Általános játékfajta
+
+Standard map
+== Általános pálya
+
+Stop record
+== Felvétel megállítása
+
+Sudden Death
+== Gyors halál
+
+Switch weapon on pickup
+== Fegyverváltás felvételnél
+
+Team
+== Csapat
+
+Team chat
+== Csapat chat
+
+Teeworlds %s is out! Download it at www.teeworlds.com!
+== Teeworlds %s kint van! Töltsd le www.teeworlds.com oldalon!
+
+Texture Compression
+== Textúra tömörítés
+
+The audio device couldn't be initialised.
+== A hangeszköz nem kezdeményezhető.
+
+The server is running a non-standard tuning on a pure game type.
+== A szerver egy nem szabványos hangolást futtat a tiszta játék típuson.
+
+There's an unsaved map in the editor, you might want to save it before you quit the game.
+== Van egy mentett térkép a szerkesztőben, talán akarod menteni, mielőtt kilépsz a játékból.
+
+Time limit
+== Időhatár
+
+Time limit: %d min
+== Időhatár: %d perc
+
+Try again
+== Próbáld újra
+
+Type
+== Típus
+
+Type:
+== Típus:
+
+UI Color
+== UI Szín
+
+Unable to delete the demo
+== Nem sikerült törölni a demó
+
+Unable to rename the demo
+== Nem sikerült átnevezni a demó
+
+Use sounds
+== Hangok használata
+
+Use team colors for name plates
+== Csapat szín használata név tábláknál
+
+V-Sync
+== V-Sync
+
+Version
+== Verzió
+
+Version:
+== Verzió:
+
+Vote command:
+== Szavazás parancsa:
+
+Vote description:
+== Szavazás leírása:
+
+Vote no
+== Nem
+
+Vote yes
+== Igen
+
+Voting
+== Szavazás
+
+Warmup
+== Kezdés
+
+Weapon
+== Fegyver
+
+Welcome to Teeworlds
+== Üdvözöljük a Teeworlds-ben
+
+Yes
+== Igen
+
+You must restart the game for all settings to take effect.
+== Újra kell indítani a játékot, a beállítások érvénybe lépéséhez.
+
+Your skin
+== Te skined
+
+no limit
+== Nincs korlát
+
+##### needs translation #####
+
+Demofile: %s
+== 
+
+Play background music
+== 
+
+Player country:
+== 
+
+Spectate next
+== 
+
+Spectate previous
+== 
+
+Strict gametype filter
+== 
+
+##### old translations #####
+
diff --git a/data/languages/index.txt b/data/languages/index.txt
index fa5862c9..b7a6179b 100644
--- a/data/languages/index.txt
+++ b/data/languages/index.txt
@@ -1,62 +1,94 @@
 
 ##### language indices #####
 
+belarusian
+== Беларуская
+== 112
+
 bosnian
 == Bosanski
+== 70
+
+brazilian_portuguese
+== Português brasileiro
+== 76
 
 bulgarian
 == Български
+== 100
 
 czech
 == Česky
+== 203
 
 danish
 == Dansk
+== 208
 
 dutch
 == Nederlands
+== 528
 
 finnish
 == Suomi
+== 246
 
 french
 == Français
+== 250
 
 german
 == Deutsch
+== 276
+
+hungarian
+== Magyar
+== 348
 
 italian
 == Italiano
+== 380
 
 norwegian
 == Norsk
+== 578
 
 polish
 == Polski
+== 616
 
 portuguese
 == Português
+== 620
 
 romanian
 == Română
+== 642
 
 russian
 == Русский
+== 643
 
 serbian
 == Srpski
+== 688
 
 slovak
 == Slovensky
+== 703
 
 spanish
 == Español
+== 724
 
 swedish
 == Svenska
+== 752
 
 turkish
 == Türkçe
+== 792
 
 ukrainian
 == Українська
+== 804
diff --git a/data/languages/italian.txt b/data/languages/italian.txt
index 4e81ec97..d566da49 100644
--- a/data/languages/italian.txt
+++ b/data/languages/italian.txt
@@ -2,31 +2,31 @@
 ##### translated strings #####
 
 %d Bytes
-== %d Bytes
+== %d byte
 
 %d of %d servers, %d players
-== %d di %d servers, %d giocatori
+== %d di %d server, %d giocatori
 
 %d%% loaded
 == %d%% caricato
 
 %ds left
-== %ds rimanenti
+== %ds sec.
 
 %i minute left
-== %i minuto residuo
+== %i minuto rimanente
 
 %i minutes left
-== %i minuti residui
+== %i minuti rimanenti
 
 %i second left
-== %i secondo residuo
+== %i secondo rimanente
 
 %i seconds left
-== %i secondi residui
+== %i secondi rimanenti
 
 %s wins!
-== %s vittorie!
+== %s ha vinto!
 
 -Page %d-
 == -Pagina %d-
@@ -38,7 +38,7 @@ Add
 == Aggiungi
 
 Add Friend
-== Aggiungi Amico
+== Aggiungi amico
 
 Address
 == Indirizzo
@@ -50,25 +50,25 @@ Alpha
 == Alpha
 
 Always show name plates
-== Mostra sempre nomi
+== Mostra sempre i nomi
 
 Are you sure that you want to delete the demo?
 == Sicuro di voler eliminare la demo?
 
 Are you sure that you want to quit?
-== Sicuro di voler uscire?
+== Sicuro di voler chiudere il gioco?
 
 Are you sure that you want to remove the player from your friends list?
-== Sicuro di voler rimuovere il giocatore dalla lista degli amici?
+== Sicuro di voler rimuovere il giocatore dalla lista di amici?
 
 As this is the first time you launch the game, please enter your nick name below. It's recommended that you check the settings to adjust them to your liking before joining a server.
-== E' la prima volta che avvii il gioco, inserisci il tuo nickname. E' bene che tu controlli le opzioni prima di giocare per avere una migliore esperienza di gioco.
+== Essendo la prima volta che avvii il gioco, ti preghiamo di inserire il tuo nickname qui sotto. Puoi cambiare le impostazioni in base alle tue preferenze prima di entrare in gioco.
 
 Automatically record demos
 == Registra automaticamente demo
 
 Automatically take game over screenshot
-== Cattura automaticamente la schermata 'game over'
+== Cattura schermata alla fine di ogni partita
 
 Blue team
 == Squadra blu
@@ -80,10 +80,10 @@ Body
 == Corpo
 
 Call vote
-== Chiama voto
+== Vota
 
 Change settings
-== Cambia configurazione
+== Cambia opzioni
 
 Chat
 == Chat
@@ -113,7 +113,7 @@ Console
 == Console
 
 Controls
-== Controlli
+== Comandi
 
 Count players only
 == Conta solo giocatori
@@ -125,7 +125,7 @@ Crc:
 == Crc:
 
 Created:
-== Creato:
+== Creata:
 
 Current
 == Attuale
@@ -145,6 +145,9 @@ Delete demo
 Demo details
 == Dettagli demo
 
+Demofile: %s
+== Demo: %s
+
 Demos
 == Demo
 
@@ -155,13 +158,13 @@ Disconnected
 == Disconnesso
 
 Display Modes
-== Modalità Display
+== Risoluzioni schermo
 
 Downloading map
-== Scaricamento mappa
+== Scaricamento mappa in corso
 
 Draw!
-== Patta!
+== Pareggio!
 
 Dynamic Camera
 == Camera dinamica
@@ -203,58 +206,58 @@ Force vote
 == Forza voto
 
 Free-View
-== Camera libera
+== Visione libera
 
 Friends
 == Amici
 
 Fullscreen
-== A tutto schermo
+== Schermo intero
 
 Game
 == Partita
 
 Game info
-== Informazioni partita
+== Info partita
 
 Game over
-== Fine partita
+== Partita finita
 
 Game type
-== Modalità di gioco
+== Tipo
 
 Game types:
-== Modalità di gioco:
+== Tipo di gioco:
 
 General
 == Generale
 
 Graphics
-== Gráfica
+== Aspetto
 
 Grenade
-== Granata
+== Lanciagranate
 
 Hammer
 == Martello
 
 Has people playing
-== Contiene giocatori
+== Con giocatori
 
 High Detail
-== Alta Risoluzione
+== Alta qualità
 
 Hook
 == Rampino
 
 Host address
-== Indirizzo Host
+== Indirizzo host
 
 Hue
 == Tinta
 
 Info
-== Informazioni
+== Info
 
 Internet
 == Internet
@@ -263,19 +266,19 @@ Invalid Demo
 == Demo non valida
 
 Join blue
-== Unisciti ai blu
+== Vai ai blu
 
 Join game
-== Unisciti alla partita
+== Entra
 
 Join red
-== Unisciti ai rossi
+== Vai ai rossi
 
 Jump
 == Salta
 
 Kick player
-== Espelli giocatore
+== Caccia giocatore
 
 LAN
 == LAN
@@ -284,7 +287,7 @@ Language
 == Lingua
 
 Length:
-== Lunghezza:
+== Durata:
 
 Lht.
 == Luminosità
@@ -302,10 +305,10 @@ Map:
 == Mappa:
 
 Max Screenshots
-== Screenshot Massimi
+== Numero massimo di catture
 
 Max demos
-== Demo massime
+== Numero massimo di demo
 
 Maximum ping:
 == Ping massimo:
@@ -314,13 +317,13 @@ Miscellaneous
 == Altro
 
 Mouse sens.
-== Sensività del mouse
+== Sensibilità
 
 Move left
 == Sinistra
 
 Move player to spectators
-== Muovi giocatore tra gli spettatori
+== Fai osservare il giocatore
 
 Move right
 == Destra
@@ -329,13 +332,13 @@ Movement
 == Movimento
 
 Mute when not active
-== Silenzioso se inattivo
+== Silenzioso quanto inattivo
 
 Name
 == Nome
 
 Name plates size
-== Lunghezza nomi
+== Dimensione nomi
 
 Netversion:
 == Versione net
@@ -344,10 +347,10 @@ New name:
 == Nuovo nome:
 
 News
-== Notizie
+== Novità
 
 Next weapon
-== Prossima arma
+== Arma seguente
 
 Nickname
 == Nickname
@@ -362,7 +365,7 @@ No servers found
 == Nessun server trovato
 
 No servers match your filter criteria
-== Nessun server rispecchia i tuoi criteri
+== Nessun server corrisponde ai tuoi criteri di ricerca
 
 Ok
 == Ok
@@ -386,11 +389,17 @@ Pistol
 == Pistola
 
 Play
-== Gioca
+== Riproduci
+
+Play background music
+== Riproduci musica di sottofondo
 
 Player
 == Giocatore
 
+Player country:
+== Filtra per paese:
+
 Player options
 == Opzioni giocatore
 
@@ -398,22 +407,22 @@ Players
 == Giocatori
 
 Please balance teams!
-== Bilancia le squadre!
+== Equilibra le squadre!
 
 Prev. weapon
 == Arma precedente
 
 Quality Textures
-== Qualità Textures
+== Texture di qualità
 
 Quick search:
 == Ricerca rapida:
 
 Quit
-== Esci
+== Chiudi
 
 Quit anyway?
-== Vuoi uscire comunque?
+== Vuoi chiudere comunque?
 
 REC %3d:%02d
 == REC %3d:%02d
@@ -428,7 +437,7 @@ Red team
 == Squadra rossa
 
 Red team wins!
-== La squadra rossa vince!
+== La squadra rossa ha vinto!
 
 Refresh
 == Aggiorna
@@ -440,13 +449,13 @@ Remote console
 == Console remota
 
 Remove
-== Rimuovi
+== Elimina
 
 Remove friend
-== Rimuovi amico
+== Elimina amico
 
 Rename
-== Renomina
+== Rinomina
 
 Rename demo
 == Rinomina demo
@@ -455,34 +464,34 @@ Reset filter
 == Azzera filtri
 
 Reset to defaults
-== Ripristina impostazioni iniziali
+== Reimposta
 
 Rifle
-== Mitra
+== Laser
 
 Round
-== Round
+== Turno
 
 Sample rate
-== Frequenza di campionamento
+== Frequenza
 
 Sat.
-== Sat.
+== Saturazione
 
 Score
-== Punteggi
+== Punti
 
 Score board
-== Tabella dei Punteggi
+== Punteggio
 
 Score limit
-== Punteggio Max.
+== Limite punti
 
 Scoreboard
-== Tabella dei Punteggi
+== Punteggi
 
 Screenshot
-== Schermata
+== Cattura schermata
 
 Server address:
 == Indirizzo server:
@@ -491,7 +500,7 @@ Server details
 == Dettagli server
 
 Server filter
-== Filtri server
+== Filtro server
 
 Server info
 == Info server
@@ -500,7 +509,7 @@ Server not full
 == Server non pieno
 
 Settings
-== Configurazioni
+== Opzioni
 
 Shotgun
 == Fucile
@@ -509,7 +518,7 @@ Show chat
 == Mostra chat
 
 Show friends only
-== Mostra amici
+== Mostra solo amici
 
 Show ingame HUD
 == Mostra HUD in gioco
@@ -521,43 +530,52 @@ Show only supported
 == Mostra solo supportati
 
 Size:
-== Dimensioni:
+== Dimensione:
 
 Skins
-== Skins
+== Skin
 
 Sound
 == Suono
 
 Sound error
-== Suono errore
+== Errore suono
 
 Sound volume
 == Volume suono
 
 Spectate
-== Spettatore
+== Osserva
+
+Spectate next
+== Osserva succ.
+
+Spectate previous
+== Osserva prec.
 
 Spectator mode
-== Modalità spettatore
+== Menu osservazione
 
 Spectators
 == Spettatori
 
 Standard gametype
-== Tipo di gioco standard
+== Tipo di gioco normale
 
 Standard map
-== Mappa standard
+== Mappa normale
 
 Stop record
-== Ferma registrazione
+== Ferma reg.
+
+Strict gametype filter
+== Tipo di gioco preciso
 
 Sudden Death
-== Morte istantanea
+== Tempo supplementare
 
 Switch weapon on pickup
-== Cambia arma automaticamente
+== Cambia arma ad ogni raccolta
 
 Team
 == Squadra
@@ -566,37 +584,37 @@ Team chat
 == Chat di squadra
 
 Teeworlds %s is out! Download it at www.teeworlds.com!
-== Teeworlds %s e' stato rilasciato! Scaricalo da www.teeworlds.com!
+== È uscito Teeworld %s! Scaricalo su www.teeworlds.com!
 
 Texture Compression
-== Compressione textures
+== Compressione texture
 
 The audio device couldn't be initialised.
 == Il dispositivo audio non può essere inizializzato.
 
 The server is running a non-standard tuning on a pure game type.
-== Il server è attivo con una configurazione non standard in una modalità di gioco pura.
+== Il server presenta impostazioni non standard in un tipo di gioco normale.
 
 There's an unsaved map in the editor, you might want to save it before you quit the game.
-== C'è una mappa non salvata nell'editor, sicuramente vorrai salvarla prima di uscire.
+== C'è una mappa non salvata nell'editor, probabilmente vuoi salvarla prima di uscire.
 
 Time limit
-== Limite tempo.
+== Limite di tempo
 
 Time limit: %d min
-== Limite tempo: %d min
+== Limite di tempo: %d min
 
 Try again
-== Riprova
+== Ritenta
 
 Type
-== Tipologia
+== Tipo
 
 Type:
-== Tipologia:
+== Tipo:
 
 UI Color
-== Colore UI
+== Color interfaccia
 
 Unable to delete the demo
 == Impossibile eliminare la demo
@@ -608,10 +626,10 @@ Use sounds
 == Attiva suoni
 
 Use team colors for name plates
-== Utilizza i colori del team per i nomi
+== Usa i colori della squadra nei nomi
 
 V-Sync
-== V-Sync
+== Sincronizzazione verticale
 
 Version
 == Versione
@@ -620,7 +638,7 @@ Version:
 == Versione:
 
 Vote command:
-== Comando voto:
+== Comando di voto:
 
 Vote description:
 == Descrizione voto:
@@ -629,10 +647,10 @@ Vote no
 == Vota no
 
 Vote yes
-== Vota si
+== Vota sì
 
 Voting
-== Votazione in corso
+== Votazione
 
 Warmup
 == Riscaldamento
@@ -641,39 +659,24 @@ Weapon
 == Arma
 
 Welcome to Teeworlds
-== Benvenuto su Teeworlds!
+== Benvenuto su Teeworlds
 
 Yes
-== Si
+== Sì
 
 You must restart the game for all settings to take effect.
-== E' necessario riavviare il gioco per impostare i cambiamenti.
+== Devi riavviare il gioco per rendere effettive le modifiche.
 
 Your skin
-== Tua skin
+== La tua skin
 
 no limit
 == senza limiti
 
 ##### needs translation #####
 
-Demofile: %s
-== 
-
-Play background music
-== 
-
-Player country:
-== 
-
-Spectate next
-== 
-
-Spectate previous
-== 
-
-Strict gametype filter
-== 
-
 ##### old translations #####
 
+
+== ## translated strings #####
+
diff --git a/data/languages/polish.txt b/data/languages/polish.txt
index 6e651e75..e955e1e6 100644
--- a/data/languages/polish.txt
+++ b/data/languages/polish.txt
@@ -1,15 +1,45 @@
 
 ##### translated strings #####
 
+%d Bytes
+== %d Bajtów
+
 %d of %d servers, %d players
 == %d z %d serwerów, %d graczy
 
+%d%% loaded
+== Załadowano %d%%
+
 %ds left
-== Jeszcze %d
+== Pozostało %ds
+
+%i minute left
+== Pozostało minut: %i
+
+%i minutes left
+== Pozostało minut: %i
+
+%i second left
+== Pozostało sekund: %i
+
+%i seconds left
+== Pozostało sekund: %i
+
+%s wins!
+== Wygrał %d!
+
+-Page %d-
+== -Strona %d-
 
 Abort
 == Anuluj
 
+Add
+== Dodaj
+
+Add Friend
+== Dodaj znajomego
+
 Address
 == Adres
 
@@ -20,19 +50,31 @@ Alpha
 == Alfa
 
 Always show name plates
-== Zawsze pokazuj nicki
+== Zawsze pokazuj nicki graczy
+
+Are you sure that you want to delete the demo?
+== Czy na pewno chcesz usunąć to demo?
 
 Are you sure that you want to quit?
 == Czy na pewno chcesz opuścić grę?
 
+Are you sure that you want to remove the player from your friends list?
+== Czy na pewno chcesz usunąć tego gracza z listy znajomych?
+
 As this is the first time you launch the game, please enter your nick name below. It's recommended that you check the settings to adjust them to your liking before joining a server.
-== To pierwsze uruchomienie gry, podaj swój nick poniżej. Zalecane jest też sprawdzenie ustawień i dopasowanie ich do siebie przed dołączeniem do gry.
+== To pierwsze uruchomienie gry, podaj swój nick poniżej. Zalecane jest też sprawdzenie ustawień i dopasowanie ich do swoich upodobań przed dołączeniem do gry.
+
+Automatically record demos
+== Automatycznie rejestruj dema
+
+Automatically take game over screenshot
+== Automatycznie zrób zrzut ekranu końca gry
 
 Blue team
-== Drużyna niebieskich
+== Niebiescy
 
 Blue team wins!
-== Drużyna niebieskich wygrała!
+== Niebiescy wygrali!
 
 Body
 == Ciało
@@ -40,9 +82,18 @@ Body
 Call vote
 == Głosowanie
 
+Change settings
+== Zmień ustawienia
+
 Chat
 == Chat
 
+Clan
+== Klan
+
+Client
+== Klient
+
 Close
 == Zamknij
 
@@ -64,6 +115,18 @@ Console
 Controls
 == Sterowanie
 
+Count players only
+== Licz tylko graczy
+
+Country
+== Kraj
+
+Crc:
+== Crc:
+
+Created:
+== Utworzono:
+
 Current
 == Aktualnie
 
@@ -71,11 +134,20 @@ Current version: %s
 == Aktualna wersja: %s
 
 Custom colors
-== Własne kolory
+== Dostosuj kolory
 
 Delete
 == Usuń
 
+Delete demo
+== Usuń demo
+
+Demo details
+== Szczegóły dema
+
+Demofile: %s
+== Plik dema: %s
+
 Demos
 == Dema
 
@@ -98,7 +170,7 @@ Dynamic Camera
 == Dynamiczna kamera
 
 Emoticon
-== Emotikonka
+== Emotikona
 
 Enter
 == Wejdź
@@ -107,10 +179,10 @@ Error
 == Błąd
 
 Error loading demo
-== Błąd przy ładowaniu demo
+== Błąd przy ładowaniu dema
 
 FSAA samples
-== próbki FSAA (anti-aliasing)
+== Próbkowanie FSAA (Antyaliasing)
 
 Favorite
 == Ulubiony
@@ -127,9 +199,18 @@ Filter
 Fire
 == Strzał
 
+Folder
+== Katalog
+
 Force vote
 == Wymuś głosowanie
 
+Free-View
+== Wolna kamera
+
+Friends
+== Znajomi
+
 Fullscreen
 == Pełny ekran
 
@@ -137,7 +218,7 @@ Game
 == Gra
 
 Game info
-== Informacje o grze
+== Info o grze
 
 Game over
 == Koniec gry
@@ -164,7 +245,7 @@ Has people playing
 == Nie pokazuj pustych
 
 High Detail
-== Wysoka jakość obrazu
+== Wysoka jakość
 
 Hook
 == Hak
@@ -181,26 +262,35 @@ Info
 Internet
 == Internet
 
+Invalid Demo
+== Nieprawidłowe demo
+
 Join blue
-== Dołącz do niebieskich
+== Do niebieskich
 
 Join game
 == Dołącz
 
 Join red
-== Dołącz do czerwonych
+== Do czerwonych
 
 Jump
 == Skok
 
+Kick player
+== Wyrzuć gracza
+
 LAN
 == LAN
 
 Language
 == Język
 
+Length:
+== Długość:
+
 Lht.
-== Jasn.
+== Jasność
 
 Loading
 == Ładowanie
@@ -211,6 +301,15 @@ MOTD
 Map
 == Mapa
 
+Map:
+== Mapa:
+
+Max Screenshots
+== Maksymalnie screenshotów
+
+Max demos
+== Maksymalnie dem
+
 Maximum ping:
 == Maksymalny ping:
 
@@ -221,22 +320,34 @@ Mouse sens.
 == Czułość myszy
 
 Move left
-== Lewo
+== W lewo
+
+Move player to spectators
+== Przesuń gracza do obserwatorów
 
 Move right
-== Prawo
+== W prawo
 
 Movement
 == Ruch
 
 Mute when not active
-== Wycisz kiedy gra nieaktywna
+== Wycisz, kiedy gra nieaktywna
 
 Name
-== Nick
+== Nazwa
+
+Name plates size
+== Wielkość wyświetlanych nicków
+
+Netversion:
+== Wersja sieciowa:
+
+New name:
+== Nowa nazwa:
 
 News
-== News
+== Wiadomości
 
 Next weapon
 == Następna broń
@@ -257,11 +368,14 @@ No servers match your filter criteria
 == Nie znaleziono serwerów spełniających twoje kryteria
 
 Ok
-== OK
+== Ok
 
 Open
 == Otwórz
 
+Parent Folder
+== Nadrzędny katalog
+
 Password
 == Hasło
 
@@ -275,16 +389,25 @@ Pistol
 == Pistolet
 
 Play
-== Start
+== Graj
+
+Play background music
+== Odtwarzaj muzykę w tle
 
 Player
 == Gracz
 
+Player country:
+== Narodowość:
+
+Player options
+== Opcje gracza
+
 Players
 == Gracze
 
 Please balance teams!
-== Konieczne wyrównanie drużyn!
+== Proszę wyrównać szanse drużyn!
 
 Prev. weapon
 == Poprzednia broń
@@ -298,11 +421,23 @@ Quick search:
 Quit
 == Wyjście
 
+Quit anyway?
+== Wyjść mimo wszystko?
+
+REC %3d:%02d
+== REC %3d:%02d
+
+Reason:
+== Powód:
+
+Record demo
+== Nagraj demo
+
 Red team
-== Drużyna czerwonych
+== Czerwoni
 
 Red team wins!
-== Drużyna czerwonych wygrała!
+== Czerwoni wygrali!
 
 Refresh
 == Odśwież
@@ -313,6 +448,18 @@ Refreshing master servers
 Remote console
 == Zdalna konsola
 
+Remove
+== Usuń
+
+Remove friend
+== Usuń znajomego
+
+Rename
+== Zmień nazwę
+
+Rename demo
+== Zmień nazwę dema
+
 Reset filter
 == Domyślne filtry
 
@@ -326,10 +473,10 @@ Round
 == Runda
 
 Sample rate
-== Próbkowanie
+== Częstotliwość próbkowania
 
 Sat.
-== Nasyc.
+== Nasycenie
 
 Score
 == Wynik
@@ -346,11 +493,17 @@ Scoreboard
 Screenshot
 == Screenshot
 
+Server address:
+== Adres serwera:
+
 Server details
 == Szczegóły serwera
 
+Server filter
+== Filtr serwerów
+
 Server info
-== Server info
+== Info serwera
 
 Server not full
 == Nie pokazuj pełnych
@@ -364,24 +517,45 @@ Shotgun
 Show chat
 == Pokaż chat
 
+Show friends only
+== Pokaż tylko znajomych
+
+Show ingame HUD
+== Pokaż wewnętrzny HUD
+
 Show name plates
 == Pokaż nicki
 
 Show only supported
 == Pokaż tylko wspierane
 
+Size:
+== Rozmiar:
+
 Skins
 == Motywy
 
 Sound
 == Dźwięk
 
+Sound error
+== Błąd dźwięku
+
 Sound volume
 == Głośność
 
 Spectate
 == Obserwuj
 
+Spectate next
+== Obserwuj następnego
+
+Spectate previous
+== Obserwuj poprzedniego
+
+Spectator mode
+== Tryb obserwatora
+
 Spectators
 == Obserwatorzy
 
@@ -391,6 +565,12 @@ Standard gametype
 Standard map
 == Standardowa mapa
 
+Stop record
+== Zakończ REC
+
+Strict gametype filter
+== Szczegółowy filtr typu gry
+
 Sudden Death
 == Nagła śmierć
 
@@ -404,35 +584,65 @@ Team chat
 == Chat drużynowy
 
 Teeworlds %s is out! Download it at www.teeworlds.com!
-== Wydano Teeworlds %s! Ściągnij je z www.teeworlds.com!
+== Nowa wersja Teeworlds %s jest dostępna! Do ściągnięcia z www.teeworlds.com!
 
 Texture Compression
 == Kompresja tekstur
 
+The audio device couldn't be initialised.
+== Urządzenie dźwiękowe nie mogło zostać zainicjowane
+
 The server is running a non-standard tuning on a pure game type.
-== Ten serwer nie korzysta ze standardowych ustawień.
+== Ten serwer korzysta z niestandardowych ustawień.
+
+There's an unsaved map in the editor, you might want to save it before you quit the game.
+== W edytorze jest niezapisana mapa! Zapisz ją, jeśli nie chcesz
 
 Time limit
 == Limit czasu
 
+Time limit: %d min
+== Limit czasu: %d min
+
 Try again
 == Ponów próbę
 
 Type
 == Typ
 
+Type:
+== Typ:
+
 UI Color
 == Kolor menu
 
+Unable to delete the demo
+== Nie można usunąć dema
+
+Unable to rename the demo
+== Nie można zmienić nazwy dema
+
 Use sounds
 == Włącz dźwięki
 
+Use team colors for name plates
+== Użyj koloru drużyn dla wyświetlania nicków
+
 V-Sync
-== V-Sync
+== Synchronizacja pionowa (V-Sync)
 
 Version
 == Wersja
 
+Version:
+== Wersja:
+
+Vote command:
+== Polecenie głosowania:
+
+Vote description:
+== Opis głosowania:
+
 Vote no
 == Nie
 
@@ -455,225 +665,18 @@ Yes
 == Tak
 
 You must restart the game for all settings to take effect.
-== Gra musi zostać uruchomiona ponownie, żeby nowe ustawienia weszły w życie.
+== Uruchom ponownie grę, aby użyć nowych ustawieńn
 
 Your skin
 == Twój wygląd
 
-##### needs translation #####
-
-%d Bytes
-== 
-
-%d%% loaded
-== 
-
-%i minute left
-== 
-
-%i minutes left
-== 
-
-%i second left
-== 
-
-%i seconds left
-== 
-
-%s wins!
-== 
-
--Page %d-
-== 
-
-Add
-== 
-
-Add Friend
-== 
-
-Are you sure that you want to delete the demo?
-== 
-
-Are you sure that you want to remove the player from your friends list?
-== 
-
-Automatically record demos
-== 
-
-Automatically take game over screenshot
-== 
-
-Change settings
-== 
-
-Clan
-== 
-
-Client
-== 
-
-Count players only
-== 
-
-Country
-== 
-
-Crc:
-== 
-
-Created:
-== 
-
-Delete demo
-== 
-
-Demo details
-== 
-
-Demofile: %s
-== 
-
-Folder
-== 
-
-Free-View
-== 
-
-Friends
-== 
-
-Invalid Demo
-== 
-
-Kick player
-== 
-
-Length:
-== 
-
-Map:
-== 
-
-Max Screenshots
-== 
-
-Max demos
-== 
-
-Move player to spectators
-== 
-
-Name plates size
-== 
-
-Netversion:
-== 
-
-New name:
-== 
-
-Parent Folder
-== 
-
-Play background music
-== 
-
-Player country:
-== 
-
-Player options
-== 
-
-Quit anyway?
-== 
-
-REC %3d:%02d
-== 
-
-Reason:
-== 
-
-Record demo
-== 
-
-Remove
-== 
-
-Remove friend
-== 
-
-Rename
-== 
-
-Rename demo
-== 
-
-Server address:
-== 
-
-Server filter
-== 
-
-Show friends only
-== 
-
-Show ingame HUD
-== 
-
-Size:
-== 
-
-Sound error
-== 
-
-Spectate next
-== 
-
-Spectate previous
-== 
-
-Spectator mode
-== 
-
-Stop record
-== 
-
-Strict gametype filter
-== 
-
-The audio device couldn't be initialised.
-== 
-
-There's an unsaved map in the editor, you might want to save it before you quit the game.
-== 
-
-Time limit: %d min
-== 
-
-Type:
-== 
-
-Unable to delete the demo
-== 
-
-Unable to rename the demo
-== 
-
-Use team colors for name plates
-== 
-
-Version:
-== 
+no limit
+== bez limitu
 
-Vote command:
-== 
+##### needs translation #####
 
-Vote description:
-== 
+##### old translations #####
 
-no limit
+utracić swojej pracy!
 == 
 
-##### old translations #####
-
diff --git a/data/languages/portuguese.txt b/data/languages/portuguese.txt
index e129a23b..e3c7c6cb 100644
--- a/data/languages/portuguese.txt
+++ b/data/languages/portuguese.txt
@@ -8,7 +8,7 @@
 == %d de %d servidores, %d jogadores
 
 %d%% loaded
-== %d%% carregado
+== %d%% A Carregar
 
 %ds left
 == faltam %ds
@@ -26,7 +26,7 @@
 == faltam %i segundos
 
 %s wins!
-== %s vence!
+== %s ganhou!
 
 -Page %d-
 == -Página %d-
@@ -50,31 +50,31 @@ Alpha
 == Alpha
 
 Always show name plates
-== Sempre mostrar apelidos
+== Mostrar sempre os nicks
 
 Are you sure that you want to delete the demo?
-== Tem certeza que deseja deletar o demo?
+== Tens a certeza que queres Eliminar a demo?
 
 Are you sure that you want to quit?
-== Você tem certeza que deseja sair?
+== Queres mesmo sair?
 
 Are you sure that you want to remove the player from your friends list?
-== Tem certeza que deseja remover o jogador da sua lista de amigos?
+== Queres mesmo apaga-lo da tua lista de amigos?
 
 As this is the first time you launch the game, please enter your nick name below. It's recommended that you check the settings to adjust them to your liking before joining a server.
-== Como esta é a primeira vez que você abre o jogo, por favor, coloque seu apelido abaixo. É recomendado que você verifique as configurações e então ajuste-as para suas preferências antes de entrar em um servidor.
+== Olá! Pelos vistos é a primeira vez que inicias o jogo, por isso escolhe um Nick Name para ti!
 
 Automatically record demos
-== Gravar demos automaticamente
+== Gravar demos Automaticamente
 
 Automatically take game over screenshot
-== Capturar tela final de jogo automaticamente
+== Tirar screenshot's Automaticamente
 
 Blue team
-== Time azul
+== Equipa azul
 
 Blue team wins!
-== Time azul vence!
+== A Equipa azul ganhou!
 
 Body
 == Corpo
@@ -104,19 +104,19 @@ Connect
 == Conectar
 
 Connecting to
-== Conectando a
+== A Conectar a
 
 Connection Problems...
-== Problemas de Conexão...
+== Problemas na conecção!
 
 Console
 == Console
 
 Controls
-== Controles
+== Controlos
 
 Count players only
-== Contar apenas jogadores
+== Só contar jogadores
 
 Country
 == País
@@ -128,22 +128,22 @@ Created:
 == Criado:
 
 Current
-== Atualmente
+== Actualmente
 
 Current version: %s
-== Versão atual : %s
+== Versão actual : %s
 
 Custom colors
 == Cores personalizadas
 
 Delete
-== Deletar
+== Eliminar
 
 Delete demo
-== Deletar demo
+== Eliminar demo
 
 Demo details
-== Detalhes do demo
+== Detalhes da demo
 
 Demofile: %s
 == Demo: %s
@@ -161,7 +161,7 @@ Display Modes
 == Modos de exibição
 
 Downloading map
-== Baixando mapa
+== A fazer download do mapa...
 
 Draw!
 == Empate!
@@ -179,7 +179,7 @@ Error
 == Erro
 
 Error loading demo
-== Erro ao carregar demo
+== Erro a carregar a demo
 
 FSAA samples
 == Amostras FSAA
@@ -197,7 +197,7 @@ Filter
 == Filtro
 
 Fire
-== Atirar
+== Disparar
 
 Folder
 == Pasta
@@ -206,13 +206,13 @@ Force vote
 == Forçar
 
 Free-View
-== Visão Livre
+== Vista Livre
 
 Friends
 == Amigos
 
 Fullscreen
-== Tela cheia
+== Fullscreen (Ecrã inteiro)
 
 Game
 == Jogo
@@ -242,7 +242,7 @@ Hammer
 == Martelo
 
 Has people playing
-== Tem gente jogando
+== Há gente a jogar
 
 High Detail
 == Mais detalhes (HD)
@@ -251,7 +251,7 @@ Hook
 == Gancho
 
 Host address
-== Endereço do host
+== Direcção do Host
 
 Hue
 == Matiz
@@ -263,37 +263,37 @@ Internet
 == Internet
 
 Invalid Demo
-== Demo inválido
+== Demo inválida
 
 Join blue
-== Azul
+== Juntar - Azuis
 
 Join game
-== Entre no jogo
+== Entrar no jogo
 
 Join red
-== Vermelho
+== J. Vermelhos
 
 Jump
-== Pular
+== Saltar
 
 Kick player
-== Kickar jogador
+== Expulsar jogador
 
 LAN
 == LAN
 
 Language
-== Idioma
+== Língua
 
 Length:
-== Duração:
+== Longitude:
 
 Lht.
 == Luz
 
 Loading
-== Carregando
+== Aguarda por favor
 
 MOTD
 == MOTD
@@ -308,7 +308,7 @@ Max Screenshots
 == Máx. de Capturas de Tela
 
 Max demos
-== Máx. de demos
+== Demos maximas
 
 Maximum ping:
 == Ping máximo:
@@ -317,13 +317,13 @@ Miscellaneous
 == Diversos
 
 Mouse sens.
-== Sens. do mouse
+== Sens. do rato
 
 Move left
 == Esquerda
 
 Move player to spectators
-== Mover jogador para observadores
+== Juntar jogador aos espectadores
 
 Move right
 == Direita
@@ -332,13 +332,13 @@ Movement
 == Movimento
 
 Mute when not active
-== Silenciar quando inativo
+== Silencíar os jogadores inactivos
 
 Name
 == Nome
 
 Name plates size
-== Tamanho dos apelidos
+== Caracteres maximos nos nicks
 
 Netversion:
 == Netversion
@@ -353,34 +353,34 @@ Next weapon
 == Próxima arma
 
 Nickname
-== Apelido
+== Nick
 
 No
 == Não
 
 No password
-== Sem senha
+== Sem password
 
 No servers found
-== Nenhum servidor encontrado
+== Nenhum servidor encontrado.
 
 No servers match your filter criteria
-== Nenhum servidor corresponde aos critérios do filtro
+== Não há servidores que correspondam às definições de procura.
 
 Ok
-== Ok
+== Aceitar
 
 Open
 == Abrir
 
 Parent Folder
-== Diretório pai
+== Pasta superior
 
 Password
-== Senha
+== Password
 
 Password incorrect
-== Senha incorreta
+== Password errada!
 
 Ping
 == Ping
@@ -389,14 +389,17 @@ Pistol
 == Pistola
 
 Play
-== Assistir
+== Ver
 
 Play background music
-== Tocar música de fundo
+== Tocar a música de fundo
 
 Player
 == Jogador
 
+Player country:
+== País do jogador
+
 Player options
 == Opções do jogador
 
@@ -404,7 +407,7 @@ Players
 == Jogadores
 
 Please balance teams!
-== Por favor, balanceie os times!
+== Equilibrem as equipas!
 
 Prev. weapon
 == Arma anterior
@@ -413,13 +416,13 @@ Quality Textures
 == Texturas de Qualidade
 
 Quick search:
-== Pesquisa rápida:
+== Busca rápida:
 
 Quit
 == Sair
 
 Quit anyway?
-== Sair mesmo assim?
+== Sair na mesma?
 
 REC %3d:%02d
 == REC %3d:%02d
@@ -428,28 +431,28 @@ Reason:
 == Motivo:
 
 Record demo
-== Gravar demo
+== Gravar uma demo
 
 Red team
-== Time vermelho
+== Equipa vermelha
 
 Red team wins!
-== Time vermelho vence!
+== Ganhou a equipa vermelha!
 
 Refresh
-== Atualizar
+== Actualizar
 
 Refreshing master servers
-== Atualizando servidores mestres
+== A Actualizar servidores
 
 Remote console
-== Console remoto
+== Remote console
 
 Remove
-== Deletar
+== Eliminar
 
 Remove friend
-== Deletar amigo
+== Deixar de ser amigo
 
 Rename
 == Renomear
@@ -458,19 +461,19 @@ Rename demo
 == Renomear demo
 
 Reset filter
-== Resetar filtro
+== Reiniciar Fitro
 
 Reset to defaults
-== Resetar para padrão
+== Por como defeito
 
 Rifle
 == Laser
 
 Round
-== Rodada
+== Ronda
 
 Sample rate
-== Taxa de som
+== Frequencia de rate
 
 Sat.
 == Sat.
@@ -479,40 +482,40 @@ Score
 == Pontos
 
 Score board
-== Placar
+== Tabela de Pontos
 
 Score limit
-== Placar máx.
+== Pontuação Máx.
 
 Scoreboard
-== Placar
+== Pontuação
 
 Screenshot
-== Captura de tela
+== Screenshot
 
 Server address:
-== End. do servidor:
+== Direção do servidor:
 
 Server details
-== Detalhes do server
+== Detalhes do servidor
 
 Server filter
-== Filtro de server
+== Filtro de servidores
 
 Server info
-== Info do server
+== Info de servidor
 
 Server not full
-== Servidor não cheio
+== Não está cheio
 
 Settings
-== Configurações
+== Config.
 
 Shotgun
 == Espingarda
 
 Show chat
-== Mostrar conversa
+== Mostrar chat
 
 Show friends only
 == Mostrar amigos
@@ -521,10 +524,10 @@ Show ingame HUD
 == Mostrar HUD do jogo
 
 Show name plates
-== Mostrar apelidos
+== Mostrar nick's
 
 Show only supported
-== Mostrar apenas suportados
+== Mostrar apenas suportado
 
 Size:
 == Tamanho:
@@ -536,10 +539,10 @@ Sound
 == Som
 
 Sound error
-== Erro de som
+== Erro no som!
 
 Sound volume
-== Volume do som
+== Volume
 
 Spectate
 == Observar
@@ -551,49 +554,49 @@ Spectate previous
 == Observar anterior
 
 Spectator mode
-== Modo Observador
+== Modo espectador
 
 Spectators
-== Observadores
+== Espectadores
 
 Standard gametype
-== Tipo de jogo padrão
+== Tipo de jogo normal
 
 Standard map
-== Mapa padrão
+== Mapa normal
 
 Stop record
 == Parar de gravar
 
 Strict gametype filter
-== Tipo de jogo exato
+== Tipo de jogo especifico
 
 Sudden Death
-== Morte Súbita
+== Morte súbita
 
 Switch weapon on pickup
-== Trocar arma ao pegar
+== Mudar de arma ao agarrar
 
 Team
-== Time
+== Equipa
 
 Team chat
-== Conv. de equipe
+== Chat de equipa
 
 Teeworlds %s is out! Download it at www.teeworlds.com!
-== Teeworlds %s foi lançado! Baixe-o em www.teeworlds.com!
+== Teeworlds %s já saiu! Download em www.teeworlds.com!
 
 Texture Compression
 == Compressão de Textura
 
 The audio device couldn't be initialised.
-== O aparelho de áudio não pode ser inicializado.
+== O dispositivo de som não pode ser iniciado.
 
 The server is running a non-standard tuning on a pure game type.
-== O servidor está rodando uma modificação não padrão em um tipo de jogo puro.
+== O servidor está a usar um tipo de jogo não oficial.
 
 There's an unsaved map in the editor, you might want to save it before you quit the game.
-== Existe um mapa não salvo no editor, você pode querer salvá-lo antes de sair do jogo.
+== O mapa que editas-te não foi gravado. Queres gravar antes de sair?
 
 Time limit
 == Tempo máx.
@@ -602,7 +605,7 @@ Time limit: %d min
 == Limite de tempo: %d min
 
 Try again
-== Tente de novo
+== Tenta outra vez
 
 Type
 == Tipo
@@ -614,16 +617,16 @@ UI Color
 == Cor do menu
 
 Unable to delete the demo
-== Incapaz de deletar demo
+== Não podes eliminar a demo
 
 Unable to rename the demo
-== Incapaz de renomear demo
+== Impossivel de renomear a demo
 
 Use sounds
 == Usar sons
 
 Use team colors for name plates
-== Usar cores do time para apelidos
+== Usar cores dos nicks com a cor da equipa
 
 V-Sync
 == V-Sync
@@ -638,7 +641,7 @@ Vote command:
 == Comando:
 
 Vote description:
-== Descrição da votação:
+== Descrição de votação:
 
 Vote no
 == Votar não
@@ -647,7 +650,7 @@ Vote yes
 == Votar sim
 
 Voting
-== Votação
+== A votar
 
 Warmup
 == Aquecimento
@@ -662,18 +665,15 @@ Yes
 == Sim
 
 You must restart the game for all settings to take effect.
-== Você deve reiniciar o jogo para que todas as alterações tenham efeito.
+== Para que as configurações sejam efectuadas deves Reiniciar o jogo.
 
 Your skin
-== Sua skin
+== A tua skin
 
 no limit
 == sem limite
 
 ##### needs translation #####
 
-Player country:
-== 
-
 ##### old translations #####
 
diff --git a/data/languages/romanian.txt b/data/languages/romanian.txt
index 41bc3774..e38faadb 100644
--- a/data/languages/romanian.txt
+++ b/data/languages/romanian.txt
@@ -332,7 +332,7 @@ Movement
 == Mișcare
 
 Mute when not active
-== Mută la inactivate
+== Opreşte sunetul la inactivate
 
 Name
 == Nume
diff --git a/data/languages/russian.txt b/data/languages/russian.txt
index 0e4a7c22..329f4a69 100644
--- a/data/languages/russian.txt
+++ b/data/languages/russian.txt
@@ -2,7 +2,7 @@
 ##### translated strings #####
 
 %d Bytes
-== %d Байтов
+== %d байт
 
 %d of %d servers, %d players
 == %d из %d серверов, %d игроков
@@ -14,19 +14,19 @@
 == осталось %d сек.
 
 %i minute left
-== %i минута осталась
+== Осталась %i минута!
 
 %i minutes left
-== %i минут осталось
+== Осталось %i минут!
 
 %i second left
-== %i секунда осталась
+== Осталась %i секунда!
 
 %i seconds left
-== %i секунд осталось
+== Осталось %i секунд!
 
 %s wins!
-== %s - победа!
+== %s победил!
 
 -Page %d-
 == -Страница %d-
@@ -47,34 +47,34 @@ All
 == Все
 
 Alpha
-== Прозрачность
+== Прозрачн.
 
 Always show name plates
-== Всегда показывать имена игроков
+== Всегда показывать ники игроков
 
 Are you sure that you want to delete the demo?
-== Вы действительно хотите удалить это демо?
+== Вы уверены, что хотите удалить демо?
 
 Are you sure that you want to quit?
-== Вы действительно хотите выйти?
+== Вы действительно желаете выйти?
 
 Are you sure that you want to remove the player from your friends list?
-== Вы действительно хотите удалить этого игрока из списка друзей?
+== Вы уверены, что хотите удалить игрока из друзей?
 
 As this is the first time you launch the game, please enter your nick name below. It's recommended that you check the settings to adjust them to your liking before joining a server.
-== Вы запустили игру первый раз, пожалуйста, введите ваш никнейм. Мы рекомендуем вам настроить игру.
+== Так как это ваш первый запуск игры, пожалуйста, введите свой ник в поле ниже. Также рекоммендуется проверить настройки игры и поменять некоторые из них перед тем, как начать играть.
 
 Automatically record demos
-== Записывать демо автоматически
+== Автоматически записывать демо
 
 Automatically take game over screenshot
-== Автоматически снимать скриншоты в конце игры
+== Делать снимок результатов игры
 
 Blue team
-== Синяя команда
+== Синие
 
 Blue team wins!
-== Синяя команда победила!
+== Синие победили!
 
 Body
 == Тело
@@ -83,7 +83,7 @@ Call vote
 == Голосовать
 
 Change settings
-== Настройки
+== Изменить настройки
 
 Chat
 == Чат
@@ -95,19 +95,19 @@ Client
 == Клиент
 
 Close
-== Закрыть
+== Выход
 
 Compatible version
 == Совместимая версия
 
 Connect
-== Играть
+== Подключиться
 
 Connecting to
-== Соединяемся с
+== Подключение к
 
 Connection Problems...
-== Проблемы с соединением...
+== Проблемы со связью...
 
 Console
 == Консоль
@@ -119,10 +119,10 @@ Count players only
 == Считать только игроков
 
 Country
-== Страна
+== Флаг вашей страны
 
 Crc:
-== Crc-сумма:
+== Crc:
 
 Created:
 == Создан:
@@ -134,7 +134,7 @@ Current version: %s
 == Текущая версия: %s
 
 Custom colors
-== Произвольный цвет
+== Свои цвета
 
 Delete
 == Удалить
@@ -143,79 +143,82 @@ Delete demo
 == Удалить демо
 
 Demo details
-== Подробности
+== Детали демо
+
+Demofile: %s
+== Демо: %s
 
 Demos
 == Демо
 
 Disconnect
-== Уйти
+== Отключить
 
 Disconnected
-== Отсоединен
+== Отключено
 
 Display Modes
-== Режим отображения
+== Разрешение экрана
 
 Downloading map
-== Загрузка карты
+== Скачивание карты
 
 Draw!
 == Ничья!
 
 Dynamic Camera
-== Динамичная Камера
+== Динамическая камера
 
 Emoticon
 == Эмоции
 
 Enter
-== Войти
+== Вход
 
 Error
 == Ошибка
 
 Error loading demo
-== Ошибка при загрузке демо
+== ошибка при загрузке демо
 
 FSAA samples
-== FSAA сэмплы
+== Сэмплов FSAA
 
 Favorite
-== Избранное
+== Избранный
 
 Favorites
-== Избранное
+== Избранные
 
 Feet
-== Нога
+== Ноги
 
 Filter
 == Фильтр
 
 Fire
-== Стрельба
+== Выстрел
 
 Folder
 == Папка
 
 Force vote
-== Форсировать голосование
+== Форсировать
 
 Free-View
-== Свободный просмотр
+== Свободный обзор
 
 Friends
-== Приятели
+== Друзья
 
 Fullscreen
-== На весь экран
+== Полноэкранный режим
 
 Game
 == Игра
 
 Game info
-== Информация о игре
+== Инфо об игре
 
 Game over
 == Игра окончена
@@ -224,7 +227,7 @@ Game type
 == Тип игры
 
 Game types:
-== Типы игры:
+== Тип игры:
 
 General
 == Основные
@@ -233,19 +236,19 @@ Graphics
 == Графика
 
 Grenade
-== Граната
+== Гранатомёт
 
 Hammer
-== Молоток
+== Молот
 
 Has people playing
-== Есть игроки на сервере
+== Не пустой сервер
 
 High Detail
-== Высокая Детализация
+== Высокая детализация
 
 Hook
-== Цепь
+== Крюк
 
 Host address
 == Адрес сервера
@@ -260,22 +263,22 @@ Internet
 == Интернет
 
 Invalid Demo
-== Невалидное демо
+== Недопустимое демо
 
 Join blue
-== К синим
+== За синих
 
 Join game
-== Войти в игру
+== Играть
 
 Join red
-== К красным
+== За красных
 
 Jump
 == Прыжок
 
 Kick player
-== Кикнуть игрока
+== Забанить игрока
 
 LAN
 == LAN
@@ -284,7 +287,7 @@ Language
 == Язык
 
 Length:
-== Длина:
+== Длина
 
 Lht.
 == Яркость
@@ -302,10 +305,10 @@ Map:
 == Карта:
 
 Max Screenshots
-== Максимум Скриншотов
+== Максимальное количество снимков
 
 Max demos
-== Максимум Демо
+== Максимальное количество демо
 
 Maximum ping:
 == Макс. пинг:
@@ -314,40 +317,40 @@ Miscellaneous
 == Дополнительно
 
 Mouse sens.
-== Чувст. мыши
+== Чувств. мыши
 
 Move left
-== Влево
+== Шаг влево
 
 Move player to spectators
-== Стать наблюдателем
+== Сделать наблюдателем
 
 Move right
-== Вправо
+== Шаг вправо
 
 Movement
-== Движение
+== Перемещение
 
 Mute when not active
-== Выключить звук когда игра неактивна
+== Глушить звуки, когда игра неактивна
 
 Name
 == Имя
 
 Name plates size
-== Размер имён над игроками
+== Размер
 
 Netversion:
 == Версия:
 
 New name:
-== Новое имя:
+== Новое имя
 
 News
 == Новости
 
 Next weapon
-== Следующее оружие
+== След. оружие
 
 Nickname
 == Ник
@@ -362,22 +365,22 @@ No servers found
 == Сервера не найдены
 
 No servers match your filter criteria
-== Нет серверов, подходящих под Ваш фильтр
+== Нет серверов, подходящих под ваш фильтр
 
 Ok
-== Ok
+== ОК
 
 Open
 == Открыть
 
 Parent Folder
-== Корневая папка
+== Родительский каталог
 
 Password
 == Пароль
 
 Password incorrect
-== Неверный пароль
+== Пароль
 
 Ping
 == Пинг
@@ -386,40 +389,43 @@ Pistol
 == Пистолет
 
 Play
-== Воспроизвести
+== Просмотр
 
 Play background music
-== Воспроизвести фоновую музыку
+== Играть фоновую музыку
 
 Player
 == Игрок
 
+Player country:
+== Страна:
+
 Player options
-== Настройки игрока
+== Опции игрока
 
 Players
 == Игроки
 
 Please balance teams!
-== Пожалуйста cбалансируйте команды!
+== Сбалансируйте команды!
 
 Prev. weapon
 == Пред. оружие
 
 Quality Textures
-== Качественные Текстуры
+== Качественные текстуры
 
 Quick search:
-== Быстрый поиск
+== Быстрый поиск:
 
 Quit
 == Выход
 
 Quit anyway?
-== Всё равно выйти?
+== Выйти?
 
 REC %3d:%02d
-== Записано %3d:%02d
+== REC %3d:%02d
 
 Reason:
 == Причина:
@@ -428,40 +434,40 @@ Record demo
 == Записать демо
 
 Red team
-== Красная команда
+== Красные
 
 Red team wins!
-== Красная команда победила!
+== Красные победили!
 
 Refresh
 == Обновить
 
 Refreshing master servers
-== Обновляем мастер-сервера
+== Обновление списка мастер-серверов
 
 Remote console
-== Серверная консоль
+== Консоль сервера
 
 Remove
 == Удалить
 
 Remove friend
-== Удалить из друзей
+== Удалить друга
 
 Rename
-== Переименовать
+== Переименов.
 
 Rename demo
 == Переименовать демо
 
 Reset filter
-== Сбросить фильтр
+== Сбросить фильтры
 
 Reset to defaults
-== Сбросить на стандартные настройки
+== Сбросить настройки
 
 Rifle
-== Лазер
+== Бластер
 
 Round
 == Раунд
@@ -476,28 +482,28 @@ Score
 == Очки
 
 Score board
-== Результат
+== Табло
 
 Score limit
-== Лимит на очки
+== Лимит очков
 
 Scoreboard
-== Результат
+== Табло
 
 Screenshot
-== Скриншот
+== Снимок
 
 Server address:
-== Адрес сервера:
+== Адрес сервера
 
 Server details
-== Информация о сервере
+== Детали сервера
 
 Server filter
-== Фильтр сервера
+== Фильтр серверов
 
 Server info
-== Инфо
+== Информация
 
 Server not full
 == Сервер не заполнен
@@ -512,22 +518,22 @@ Show chat
 == Показать чат
 
 Show friends only
-== Показывать друзей
+== Только с друзьями
 
 Show ingame HUD
-== Показывать HUD
+== Показывать внутриигровой HUD
 
 Show name plates
-== Показывать имена над игроками
+== Показывать ники игроков
 
 Show only supported
-== Показывать только поддерживаемые
+== Показывать только поддерживаемые разрешения экрана
 
 Size:
-== Размер
+== Размер:
 
 Skins
-== Модели
+== Скины
 
 Sound
 == Звук
@@ -536,16 +542,16 @@ Sound error
 == Звуковая ошибка
 
 Sound volume
-== Громкость
+== Громкость звука
 
 Spectate
 == Наблюдать
 
 Spectate next
-== Наблюдать следующего
+== Наблюдать след.
 
 Spectate previous
-== Наблюдать предыдущего
+== Наблюдать пред.
 
 Spectator mode
 == Наблюдатель
@@ -560,13 +566,16 @@ Standard map
 == Стандартная карта
 
 Stop record
-== Остановить запись
+== Стоп
+
+Strict gametype filter
+== Строгий фильтр режим.
 
 Sudden Death
-== Внезапная смерть
+== Быстрая смерть
 
 Switch weapon on pickup
-== Сменить оружие на подобранное
+== Переключать оружие при подборе
 
 Team
 == Команда
@@ -575,28 +584,28 @@ Team chat
 == Командный чат
 
 Teeworlds %s is out! Download it at www.teeworlds.com!
-== Teeworlds %s в сети! Скачайте его на www.teeworlds.com!
+== Вышла Teeworlds %s! Скачивайте на www.teeworlds.com!
 
 Texture Compression
 == Сжатие текстур
 
 The audio device couldn't be initialised.
-== Аудио устройство не может быть инициализировано.
+== Аудио устройство не может быть инициализировано
 
 The server is running a non-standard tuning on a pure game type.
-== Этот сервер работает на нестандартных настройках стандартного типа игры.
+== Сервер запущен с нестандартными настройками на стандартном типе игры.
 
 There's an unsaved map in the editor, you might want to save it before you quit the game.
-== В редакторе есть несохранённая карта
+== Есть несохранённая карта в редакторе, Вы можете сохранить её перед тем, как выйти.
 
 Time limit
-== Лимит на время
+== Лимит времени
 
 Time limit: %d min
-== Лимит на время: %d мин
+== Лимит времени: %d
 
 Try again
-== Попробовать ещё раз
+== ОК
 
 Type
 == Тип
@@ -614,10 +623,10 @@ Unable to rename the demo
 == Невозможно переименовать демо
 
 Use sounds
-== Звук
+== Использовать звуки
 
 Use team colors for name plates
-== Использовать цвет команды для имён игроков
+== Командные цвета для ников игроков
 
 V-Sync
 == Вертикальная синхронизация
@@ -629,10 +638,10 @@ Version:
 == Версия:
 
 Vote command:
-== Голосование:
+== Комманда голосования:
 
 Vote description:
-== Причина голосования:
+== Описание голосования:
 
 Vote no
 == Против
@@ -644,7 +653,7 @@ Voting
 == Голосование
 
 Warmup
-== Разогрев
+== Разминка
 
 Weapon
 == Оружие
@@ -656,7 +665,7 @@ Yes
 == Да
 
 You must restart the game for all settings to take effect.
-== Вы должны перезапустить игру, чтобы настройки применились.
+== Перезапустите игру для применения изменений.
 
 Your skin
 == Ваш скин
@@ -666,14 +675,5 @@ no limit
 
 ##### needs translation #####
 
-Demofile: %s
-== 
-
-Player country:
-== 
-
-Strict gametype filter
-== 
-
 ##### old translations #####
 
diff --git a/data/languages/serbian.txt b/data/languages/serbian.txt
index 64c8fb37..e4ec95c2 100644
--- a/data/languages/serbian.txt
+++ b/data/languages/serbian.txt
@@ -1,15 +1,45 @@
 
 ##### translated strings #####
 
+%d Bytes
+== %d Bytes
+
 %d of %d servers, %d players
 == %d od %d server(a), %d igrač(a)
 
+%d%% loaded
+== Učitano %d%%
+
 %ds left
 == Još %ds
 
+%i minute left
+== Još %ds
+
+%i minutes left
+== Preostalo: %i min.
+
+%i second left
+== Preostalo: %i min.
+
+%i seconds left
+== Preostalo: %i sek.
+
+%s wins!
+== %s je pobijedio!
+
+-Page %d-
+== -Strana %d-
+
 Abort
 == Prekini
 
+Add
+== Dodaj
+
+Add Friend
+== Dodaj prijatelja
+
 Address
 == Adresa
 
@@ -22,12 +52,24 @@ Alpha
 Always show name plates
 == Uvek prikaži imena igrača
 
+Are you sure that you want to delete the demo?
+== Da li sigurni da želite da obrišete demo-snimak?
+
 Are you sure that you want to quit?
 == Jeste li sigurni da želite da izađete?
 
+Are you sure that you want to remove the player from your friends list?
+== Da li ste sigurni da želite da obrišete igrača iz liste prijatelja?
+
 As this is the first time you launch the game, please enter your nick name below. It's recommended that you check the settings to adjust them to your liking before joining a server.
 == Pošto prvi put pokrećete igru, molimo da ispod unesete Vaš nadimak (nick). Preporučujemo da proverite podešavanja i podesite ih prema Vašem ukusu pre nego što se konektujete na server.
 
+Automatically record demos
+== Automatski snimi demo
+
+Automatically take game over screenshot
+== Automatski napravi screenshot
+
 Blue team
 == Plavi tim
 
@@ -40,9 +82,18 @@ Body
 Call vote
 == Glasanje
 
+Change settings
+== Izmeni podešavanja
+
 Chat
 == Chat
 
+Clan
+== Klan
+
+Client
+== Klijent
+
 Close
 == Zatvori
 
@@ -64,6 +115,18 @@ Console
 Controls
 == Kontrole
 
+Count players only
+== Izbroj samo igrače
+
+Country
+== Država
+
+Crc:
+== Crc:
+
+Created:
+== Kreirano:
+
 Current
 == Trenutno
 
@@ -76,6 +139,15 @@ Custom colors
 Delete
 == Izbriši
 
+Delete demo
+== Obriši demo-snimak
+
+Demo details
+== Detalji demo-a
+
+Demofile: %s
+== Demo-snimak: %s
+
 Demos
 == Demoi
 
@@ -127,9 +199,18 @@ Filter
 Fire
 == Pucanje
 
+Folder
+== Direktorijum
+
 Force vote
 == Obavezno glasanje
 
+Free-View
+== Slobodan pregled
+
+Friends
+== Prijatelji
+
 Fullscreen
 == Čitav ekran
 
@@ -181,6 +262,9 @@ Info
 Internet
 == Internet
 
+Invalid Demo
+== Neispravan demo-snimak
+
 Join blue
 == U plavi tim
 
@@ -193,12 +277,18 @@ Join red
 Jump
 == Skok
 
+Kick player
+== Izbaci igrača iz igre
+
 LAN
 == LAN
 
 Language
 == Jezik
 
+Length:
+== Dužina:
+
 Lht.
 == Svetl.
 
@@ -211,6 +301,15 @@ MOTD
 Map
 == Mapa
 
+Map:
+== Mapa:
+
+Max Screenshots
+== Maksimalan broj screenshot-ova
+
+Max demos
+== Maksimalan broj demo-a
+
 Maximum ping:
 == Maksimalan ping:
 
@@ -223,6 +322,9 @@ Mouse sens.
 Move left
 == Nalevo
 
+Move player to spectators
+== Prebaci igrača u posmatrače
+
 Move right
 == Nadesno
 
@@ -235,6 +337,15 @@ Mute when not active
 Name
 == Ime
 
+Name plates size
+== Veličina pozadine za ime
+
+Netversion:
+== Net-verzija:
+
+New name:
+== Novo ime:
+
 News
 == Novosti
 
@@ -259,6 +370,12 @@ No servers match your filter criteria
 Ok
 == OK
 
+Open
+== Otvori
+
+Parent Folder
+== Prethodni direktorijum
+
 Password
 == Lozinka
 
@@ -274,9 +391,18 @@ Pistol
 Play
 == Pokreni
 
+Play background music
+== Pozadinska muzika
+
 Player
 == Igrač
 
+Player country:
+== Država
+
+Player options
+== Podešavanja igrača
+
 Players
 == Igrači
 
@@ -295,6 +421,18 @@ Quick search:
 Quit
 == Izlaz
 
+Quit anyway?
+== Izlaz?
+
+REC %3d:%02d
+== REC %3d:%02d
+
+Reason:
+== Razlog:
+
+Record demo
+== Snimi demo
+
 Red team
 == Crveni tim
 
@@ -310,6 +448,18 @@ Refreshing master servers
 Remote console
 == Udaljena konzola
 
+Remove
+== Ukloni
+
+Remove friend
+== Ukloni prijatelja
+
+Rename
+== Preimenuj
+
+Rename demo
+== Preimenuj demo-snimak
+
 Reset filter
 == Poništi filter
 
@@ -343,9 +493,15 @@ Scoreboard
 Screenshot
 == Screenshot
 
+Server address:
+== Adresa servera:
+
 Server details
 == Podaci o serveru
 
+Server filter
+== Filter servera
+
 Server info
 == O Serveru
 
@@ -361,24 +517,45 @@ Shotgun
 Show chat
 == Prikaži chat
 
+Show friends only
+== Prikaži isključivo prijatelje
+
+Show ingame HUD
+== Prikaži HUD
+
 Show name plates
 == Prikaži imena igrača
 
 Show only supported
 == Prikaži samo podržane
 
+Size:
+== Veličina:
+
 Skins
 == Izgled
 
 Sound
 == Zvuk
 
+Sound error
+== Problem sa zvukom
+
 Sound volume
 == Jačina zvuka
 
 Spectate
 == Posmatraj
 
+Spectate next
+== Posmatraj narednog
+
+Spectate previous
+== Posmatraj prethodnog
+
+Spectator mode
+== Posmatrački mod
+
 Spectators
 == Posmatrači
 
@@ -388,6 +565,12 @@ Standard gametype
 Standard map
 == Standardna mapa
 
+Stop record
+== Prekini snimanje
+
+Strict gametype filter
+== Striktan filter tipa igre
+
 Sudden Death
 == Iznenadna smrt
 
@@ -406,30 +589,60 @@ Teeworlds %s is out! Download it at www.teeworlds.com!
 Texture Compression
 == Kompresija tekstura
 
+The audio device couldn't be initialised.
+== Audio-uređaj nije moguće pokrenuti.
+
 The server is running a non-standard tuning on a pure game type.
 == Server sadrži nestandardna podešavanja.
 
+There's an unsaved map in the editor, you might want to save it before you quit the game.
+== Mapa u editoru nije zapamćena, možda želite da je zapamtite pre izlaska iz igre.
+
 Time limit
 == Max. vremena
 
+Time limit: %d min
+== Vremensko ograničenje: %d min.
+
 Try again
 == Pokušaj ponovo
 
 Type
 == Tip
 
+Type:
+== Tip:
+
 UI Color
 == Boja menija
 
+Unable to delete the demo
+== Demo-snimak nije moguće obrisati
+
+Unable to rename the demo
+== Demo-snimak nije moguće preimenovati
+
 Use sounds
 == Aktiviraj zvuk
 
+Use team colors for name plates
+== Koristi timsku boju u prikazu imena
+
 V-Sync
 == V-Sync
 
 Version
 == Verzija
 
+Version:
+== Verzija:
+
+Vote command:
+== Komanda za glasanje:
+
+Vote description:
+== Opis glasanja:
+
 Vote no
 == Ne
 
@@ -457,223 +670,10 @@ You must restart the game for all settings to take effect.
 Your skin
 == Vaš izgled
 
-##### needs translation #####
-
-%d Bytes
-== 
-
-%d%% loaded
-== 
-
-%i minute left
-== 
-
-%i minutes left
-== 
-
-%i second left
-== 
-
-%i seconds left
-== 
-
-%s wins!
-== 
-
--Page %d-
-== 
-
-Add
-== 
-
-Add Friend
-== 
-
-Are you sure that you want to delete the demo?
-== 
-
-Are you sure that you want to remove the player from your friends list?
-== 
-
-Automatically record demos
-== 
-
-Automatically take game over screenshot
-== 
-
-Change settings
-== 
-
-Clan
-== 
-
-Client
-== 
-
-Count players only
-== 
-
-Country
-== 
-
-Crc:
-== 
-
-Created:
-== 
-
-Delete demo
-== 
-
-Demo details
-== 
-
-Demofile: %s
-== 
-
-Folder
-== 
-
-Free-View
-== 
-
-Friends
-== 
-
-Invalid Demo
-== 
-
-Kick player
-== 
-
-Length:
-== 
-
-Map:
-== 
-
-Max Screenshots
-== 
-
-Max demos
-== 
-
-Move player to spectators
-== 
-
-Name plates size
-== 
-
-Netversion:
-== 
-
-New name:
-== 
-
-Open
-== 
-
-Parent Folder
-== 
-
-Play background music
-== 
-
-Player country:
-== 
-
-Player options
-== 
-
-Quit anyway?
-== 
-
-REC %3d:%02d
-== 
-
-Reason:
-== 
-
-Record demo
-== 
-
-Remove
-== 
-
-Remove friend
-== 
-
-Rename
-== 
-
-Rename demo
-== 
-
-Server address:
-== 
-
-Server filter
-== 
-
-Show friends only
-== 
-
-Show ingame HUD
-== 
-
-Size:
-== 
-
-Sound error
-== 
-
-Spectate next
-== 
-
-Spectate previous
-== 
-
-Spectator mode
-== 
-
-Stop record
-== 
-
-Strict gametype filter
-== 
-
-The audio device couldn't be initialised.
-== 
-
-There's an unsaved map in the editor, you might want to save it before you quit the game.
-== 
-
-Time limit: %d min
-== 
-
-Type:
-== 
-
-Unable to delete the demo
-== 
-
-Unable to rename the demo
-== 
-
-Use team colors for name plates
-== 
-
-Version:
-== 
-
-Vote command:
-== 
-
-Vote description:
-== 
-
 no limit
-== 
+== bez ograničenja
+
+##### needs translation #####
 
 ##### old translations #####
 
diff --git a/data/languages/slovak.txt b/data/languages/slovak.txt
index 57f96e25..48816234 100644
--- a/data/languages/slovak.txt
+++ b/data/languages/slovak.txt
@@ -14,16 +14,16 @@
 == Zostáva %ds
 
 %i minute left
-== Zostáva %i minúta
+== Zostávajúce minúty: %i
 
 %i minutes left
-== Zostáva %i minút
+== Zostávajúce minúty: %i
 
 %i second left
-== Zostáva %i sekunda
+== Zostávajúce sekundy: %i
 
 %i seconds left
-== Zostáva %i sekúnd
+== Zostávajúce sekundy: %i
 
 %s wins!
 == %s vyhráva!
@@ -62,7 +62,7 @@ Are you sure that you want to remove the player from your friends list?
 == Ste si istí, že chcete tohto hráča odstrániť zo zoznamu priateľov?
 
 As this is the first time you launch the game, please enter your nick name below. It's recommended that you check the settings to adjust them to your liking before joining a server.
-== Vitajte v hre TeeWorlds. Pred tým, ako sa pripojíte na herný server, odporúčame nastaviť si hru podľa svojich požiadavkov. Napíšte do políčka nižšie meno pre Vášho tee a pokračujte kliknutím na tlačítko.
+== Vitajte v hre TeeWorlds. Predtým, ako sa pripojíte na herný server, odporúčame nastaviť si hru podľa svojich požiadavkov. Napíšte do políčka nižšie meno pre Vášho tee a pokračujte kliknutím na tlačítko.
 
 Automatically record demos
 == Automaticky nahrávať záznamy
@@ -116,7 +116,7 @@ Controls
 == Ovládanie
 
 Count players only
-== Rátať len hráčov
+== Nepočítať divákov
 
 Country
 == Krajina
@@ -145,6 +145,9 @@ Delete demo
 Demo details
 == Detaily nahrávky
 
+Demofile: %s
+== Nahrávka: %s
+
 Demos
 == Záznamy
 
@@ -254,7 +257,7 @@ Hue
 == Hue
 
 Info
-== Informácie
+== Info
 
 Internet
 == Internet
@@ -320,7 +323,7 @@ Move left
 == Pohyb vľavo
 
 Move player to spectators
-== Presunúť hráča do skupiny divákov
+== Poslať hráča pozorovať
 
 Move right
 == Pohyb vpravo
@@ -365,7 +368,7 @@ No servers match your filter criteria
 == Žiadny server nezodpovedá zadaným kritériám
 
 Ok
-== Ok
+== OK
 
 Open
 == Otvoriť
@@ -388,9 +391,15 @@ Pistol
 Play
 == Prehrať
 
+Play background music
+== Prehrať hudbu na pozadí
+
 Player
 == Hráč
 
+Player country:
+== Filter krajín:
+
 Player options
 == Nastavenia hráča
 
@@ -407,7 +416,7 @@ Quality Textures
 == Kvalitné textúry
 
 Quick search:
-== Rýchle hľadanie:
+== Hľadanie:
 
 Quit
 == Ukončiť
@@ -473,13 +482,13 @@ Score
 == Skóre
 
 Score board
-== Prehľad skóre
+== Tabuľka výsledkov
 
 Score limit
 == Limit skóre
 
 Scoreboard
-== Prehľad skóre
+== Tabuľka výsledkov
 
 Screenshot
 == Screenshot
@@ -527,7 +536,7 @@ Skins
 == Skiny
 
 Sound
-== Zvuky
+== Zvuk
 
 Sound error
 == Zvuková chyba
@@ -538,6 +547,12 @@ Sound volume
 Spectate
 == Pozorovať
 
+Spectate next
+== Pozorovať ďalšieho
+
+Spectate previous
+== Pozorovať predch.
+
 Spectator mode
 == Mód diváka
 
@@ -545,14 +560,17 @@ Spectators
 == Diváci
 
 Standard gametype
-== Štandartný herný typ
+== Štandardný herný typ
 
 Standard map
-== Štandartná mapa
+== Štandardná mapa
 
 Stop record
 == Nenahrávať
 
+Strict gametype filter
+== Striktný filter módov
+
 Sudden Death
 == Rýchla Smrť
 
@@ -560,7 +578,7 @@ Switch weapon on pickup
 == Nastavovať zdvíhanú zbraň ako aktuálnu
 
 Team
-== Tým
+== Týmu
 
 Team chat
 == Týmový chat
@@ -575,10 +593,10 @@ The audio device couldn't be initialised.
 == Zvukové zariadenie nemohlo byť inicializované.
 
 The server is running a non-standard tuning on a pure game type.
-== Na serveri je nastavený neštandartný tuning.
+== Server používa neštandardné nastavenia na základnom hernom móde.
 
 There's an unsaved map in the editor, you might want to save it before you quit the game.
-== V editore máte neuloženú mapu, mali by ste si ju uložiť predtým než skončíte hru.
+== V editore máte neuloženú mapu, možno si ju chcete pred skončením hry uložiť.
 
 Time limit
 == Časový limit
@@ -602,7 +620,7 @@ Unable to delete the demo
 == Nemôžem vymazať záznam
 
 Unable to rename the demo
-== Nedá sa premenovať nahrávka
+== Nahrávka sa nedá premenovať
 
 Use sounds
 == Povoliť zvuky
@@ -626,10 +644,10 @@ Vote description:
 == Popis hlasu:
 
 Vote no
-== Hlasovať proti
+== Nie
 
 Vote yes
-== Hlasovať pre
+== Áno
 
 Voting
 == Hlasovanie
@@ -638,7 +656,7 @@ Warmup
 == Rozohrávka
 
 Weapon
-== Zbraň
+== Zbrane
 
 Welcome to Teeworlds
 == Vitajte v hre Teeworlds!
@@ -657,23 +675,5 @@ no limit
 
 ##### needs translation #####
 
-Demofile: %s
-== 
-
-Play background music
-== 
-
-Player country:
-== 
-
-Spectate next
-== 
-
-Spectate previous
-== 
-
-Strict gametype filter
-== 
-
 ##### old translations #####
 
diff --git a/data/languages/spanish.txt b/data/languages/spanish.txt
index f54dc175..5348d16a 100644
--- a/data/languages/spanish.txt
+++ b/data/languages/spanish.txt
@@ -2,7 +2,7 @@
 ##### translated strings #####
 
 %d Bytes
-== %d Bytes
+== %d bytes
 
 %d of %d servers, %d players
 == %d de %d servidores, %d jugadores
@@ -11,22 +11,22 @@
 == %d%% cargado
 
 %ds left
-== faltan %ds
+== %ds restantes
 
 %i minute left
-== falta %i minuto
+== %i minuto restante
 
 %i minutes left
-== faltan %i minutos
+== %i minutos restantes
 
 %i second left
-== falta %i segundo
+== %i segundo restante
 
 %i seconds left
-== faltan %i segundos
+== %i segundos restantes
 
 %s wins!
-== %s gana!
+== ¡%s gana!
 
 -Page %d-
 == -Página %d-
@@ -38,7 +38,7 @@ Add
 == Añadir
 
 Add Friend
-== Añadir Amigo
+== Añadir amigo
 
 Address
 == Dirección
@@ -53,40 +53,40 @@ Always show name plates
 == Mostrar siempre los apodos
 
 Are you sure that you want to delete the demo?
-== ¿Seguro que quiere eliminar la demo?
+== ¿Estás seguro de que quieres eliminar la demo?
 
 Are you sure that you want to quit?
-== ¿Seguro que quiere salir?
+== ¿Estás seguro de que quieres salir?
 
 Are you sure that you want to remove the player from your friends list?
-== ¿Estas seguro de que quiere eliminar este jugador de su lista de amigos?
+== ¿Estás seguro de que quieres eliminar a este jugador de la lista de amigos?
 
 As this is the first time you launch the game, please enter your nick name below. It's recommended that you check the settings to adjust them to your liking before joining a server.
-== Como es la primera vez que abre el juego, por favor, introduzca su apodo. Es recomendable que verifique su configuración y ajuste las preferencias antes de entrar en un servidor.
+== Como es la primera vez que abres el juego, por favor, introduce tu apodo. Es recomendable que verifiques tu configuración y ajustes las preferencias antes de unirte a un servidor.
 
 Automatically record demos
 == Grabar demos automáticamente
 
 Automatically take game over screenshot
-== Pantallazo 'game over' automáticamente
+== Captura de pantalla al final de la partida
 
 Blue team
 == Equipo azul
 
 Blue team wins!
-== Equipo azul gana!
+== ¡El equipo azul gana!
 
 Body
 == Cuerpo
 
 Call vote
-== Votación
+== Votar
 
 Change settings
 == Cambiar configuración
 
 Chat
-== Charla
+== Conversación
 
 Clan
 == Clan
@@ -107,7 +107,7 @@ Connecting to
 == Conectando con
 
 Connection Problems...
-== Problemas de Conexión...
+== Problemas de conexión...
 
 Console
 == Consola
@@ -119,16 +119,16 @@ Count players only
 == Solo contar jugadores
 
 Country
-== Pais
+== País
 
 Crc:
-== Crc:
+== CRC:
 
 Created:
 == Creado:
 
 Current
-== Actualmente
+== Actual
 
 Current version: %s
 == Versión actual: %s
@@ -143,7 +143,10 @@ Delete demo
 == Borrar demo
 
 Demo details
-== Detellades demo
+== Detalles de la demo
+
+Demofile: %s
+== Archivo: %s
 
 Demos
 == Demos
@@ -155,13 +158,13 @@ Disconnected
 == Desconectado
 
 Display Modes
-== Modos de exibición
+== Modos de video
 
 Downloading map
-== Bajando mapa
+== Descargando mapa
 
 Draw!
-== Empate!
+== ¡Empate!
 
 Dynamic Camera
 == Cámara dinámica
@@ -176,7 +179,7 @@ Error
 == Error
 
 Error loading demo
-== Error al cargar demo
+== Error al cargar la demo
 
 FSAA samples
 == Muestras FSAA
@@ -203,25 +206,25 @@ Force vote
 == Forzar
 
 Free-View
-== Vista Libre
+== Vista libre
 
 Friends
 == Amigos
 
 Fullscreen
-== Pantalla Completa
+== Pantalla completa
 
 Game
 == Juego
 
 Game info
-== Info. sobre el juego
+== Información del juego
 
 Game over
-== Fin del Juego
+== Fin de la partida
 
 Game type
-== Tipo de juego
+== Modo
 
 Game types:
 == Tipos de juego:
@@ -248,13 +251,13 @@ Hook
 == Gancho
 
 Host address
-== Dirección de host
+== Dirección del host
 
 Hue
 == Matiz
 
 Info
-== Info.
+== Información
 
 Internet
 == Internet
@@ -263,13 +266,13 @@ Invalid Demo
 == Demo inválida
 
 Join blue
-== Azul
+== Unirse a azul
 
 Join game
-== Entrar al juego
+== Unirse
 
 Join red
-== Rojo
+== Unirse a rojo
 
 Jump
 == Saltar
@@ -287,7 +290,7 @@ Length:
 == Longitud:
 
 Lht.
-== Luz
+== Luminosidad
 
 Loading
 == Cargando
@@ -302,10 +305,10 @@ Map:
 == Mapa:
 
 Max Screenshots
-== Max Pantallazos
+== Número máximo de capturas
 
 Max demos
-== Max demos
+== Número máximo de demos
 
 Maximum ping:
 == Ping máximo:
@@ -314,40 +317,40 @@ Miscellaneous
 == Miscelánea
 
 Mouse sens.
-== Sens. del ratón
+== Sensibilidad ratón
 
 Move left
-== Izquierda
+== Mover a la izquierda
 
 Move player to spectators
 == Mover jugador a espectadores
 
 Move right
-== Derecha
+== Mover a la derecha
 
 Movement
 == Movimiento
 
 Mute when not active
-== Silenciar en inactivo
+== Silenciar si no está activo
 
 Name
 == Nombre
 
 Name plates size
-== Máx. Caracteres para los Apodos
+== Tamaño de la fuente de los apodos
 
 Netversion:
 == Versión Net
 
 New name:
-== Nuevo Nombre:
+== Nuevo nombre:
 
 News
-== Notícia
+== Noticias
 
 Next weapon
-== Próxima arma
+== Arma siguiente
 
 Nickname
 == Apodo
@@ -362,7 +365,7 @@ No servers found
 == Ningún servidor encontrado
 
 No servers match your filter criteria
-== Ningún servidor corresponde a los critérios de filtrado
+== Ningún servidor corresponde a los criterios de filtrado
 
 Ok
 == Aceptar
@@ -371,7 +374,7 @@ Open
 == Abrir
 
 Parent Folder
-== Carpeta superior
+== Directorio padre
 
 Password
 == Contraseña
@@ -386,19 +389,25 @@ Pistol
 == Pistola
 
 Play
-== Asistir
+== Reproducir
+
+Play background music
+== Reproducir música de fondo
 
 Player
 == Jugador
 
+Player country:
+== País del jugador
+
 Player options
-== Opciones de Jugador
+== Opciones de jugador
 
 Players
 == Jugadores
 
 Please balance teams!
-== Por favor, equilibre los equipos!
+== Por favor, ¡equilibrad los equipos!
 
 Prev. weapon
 == Arma anterior
@@ -407,7 +416,7 @@ Quality Textures
 == Texturas de calidad
 
 Quick search:
-== Busqueda rápida:
+== Búsqueda rápida:
 
 Quit
 == Salir
@@ -428,7 +437,7 @@ Red team
 == Equipo rojo
 
 Red team wins!
-== Ganó el Equipo rojo!
+== ¡El equipo rojo gana!
 
 Refresh
 == Actualizar
@@ -458,7 +467,7 @@ Reset to defaults
 == Resetar por defecto
 
 Rifle
-== Laser
+== Láser
 
 Round
 == Ronda
@@ -467,40 +476,40 @@ Sample rate
 == Frecuencia de muestreo
 
 Sat.
-== Sat.
+== Saturación
 
 Score
 == Puntos
 
 Score board
-== Tabla de puntos
+== Puntuación
 
 Score limit
-== Puntuación Máx.
+== Límite puntos
 
 Scoreboard
 == Puntuación
 
 Screenshot
-== Pantallazo
+== Captura de pantalla
 
 Server address:
-== Dirección d. servidor:
+== IP del servidor:
 
 Server details
-== Detalles del server
+== Detalles del servidor
 
 Server filter
 == Filtro del servidor
 
 Server info
-== Info del server
+== Servidor
 
 Server not full
-== Servidor incompleto
+== Servidor sin llenar
 
 Settings
-== Config.
+== Configuración
 
 Shotgun
 == Escopeta
@@ -509,16 +518,16 @@ Show chat
 == Mostrar chat
 
 Show friends only
-== Mostrar amigos
+== Solo mostrar amigos
 
 Show ingame HUD
-== Mostar HUD en juego
+== Mostar HUD durante el juego
 
 Show name plates
 == Mostrar apodos
 
 Show only supported
-== Mostrar solo soportados
+== Mostrar únicamente modos soportados
 
 Size:
 == Tamaño:
@@ -536,58 +545,67 @@ Sound volume
 == Volumen de sonido
 
 Spectate
-== Observar
+== Asistir
+
+Spectate next
+== Observar siguiente
+
+Spectate previous
+== Observar anterior
 
 Spectator mode
 == Modo espectador
 
 Spectators
-== Observadores
+== Espectadores
 
 Standard gametype
-== Tipo de juego normal
+== Tipo de juego estándar
 
 Standard map
-== Mapa normal
+== Mapa estándar
 
 Stop record
-== Parar grabación
+== Detener grabación
+
+Strict gametype filter
+== Tipo de juego del filtro
 
 Sudden Death
-== Muerte Súbita
+== Muerte súbita
 
 Switch weapon on pickup
-== Cambiar de arma
+== Cambiar al arma recogida
 
 Team
 == Equipo
 
 Team chat
-== Conv. de equipo
+== En equipo
 
 Teeworlds %s is out! Download it at www.teeworlds.com!
-== Teeworlds %s ya salió! Descárgalo desde www.teeworlds.com!
+== ¡Teeworlds %s ha salido! ¡Descárgalo desde www.teeworlds.com!
 
 Texture Compression
-== Compresión de Textura
+== Compresión de texturas
 
 The audio device couldn't be initialised.
 == El dispositivo de audio no puede ser inicializado.
 
 The server is running a non-standard tuning on a pure game type.
-== El servidor está ejecutando una afinación no estándar en un tipo de juego puro.
+== El servidor está ejecutando una configuración no estándar en un tipo de juego puro.
 
 There's an unsaved map in the editor, you might want to save it before you quit the game.
-== Tienes un mapa sin guardar en el editor, ¿quiere guardarlo antes de salir?
+== Tienes un mapa sin guardar en el editor, quizá quieras guardarlo antes de salir.
 
 Time limit
-== Tiempo máx.
+== Tiempo límite
 
 Time limit: %d min
-== Tiempo limite: %d min
+== Tiempo límite: %d minutos
 
 Try again
-== Probar de nuevo
+== Intentar de nuevo
 
 Type
 == Tipo
@@ -596,19 +614,19 @@ Type:
 == Tipo:
 
 UI Color
-== Color de menu
+== Color de menú
 
 Unable to delete the demo
-== No se puede eliminar la demo
+== No se pudo eliminar la demo
 
 Unable to rename the demo
-== Imposible renombrar la demo
+== No se pudo renombrar la demo
 
 Use sounds
 == Usar sonidos
 
 Use team colors for name plates
-== Usar el color del equipo en los apodos
+== Usar el color de equipo en los apodos
 
 V-Sync
 == V-Sync
@@ -620,7 +638,7 @@ Version:
 == Versión:
 
 Vote command:
-== Votar comando:
+== Comando de votación:
 
 Vote description:
 == Descripción de la votación:
@@ -629,10 +647,10 @@ Vote no
 == Votar no
 
 Vote yes
-== Votar si
+== Votar sí
 
 Voting
-== Votando
+== Votación
 
 Warmup
 == Calentamiento
@@ -641,10 +659,10 @@ Weapon
 == Arma
 
 Welcome to Teeworlds
-== Bienvenido a Teeworlds!
+== ¡Bienvenido/a a Teeworlds!
 
 Yes
-== Si
+== Sí
 
 You must restart the game for all settings to take effect.
 == Debes reiniciar el juego para que los cambios tengan efecto.
@@ -657,23 +675,5 @@ no limit
 
 ##### needs translation #####
 
-Demofile: %s
-== 
-
-Play background music
-== 
-
-Player country:
-== 
-
-Spectate next
-== 
-
-Spectate previous
-== 
-
-Strict gametype filter
-== 
-
 ##### old translations #####
 
diff --git a/data/languages/swedish.txt b/data/languages/swedish.txt
index 38bde2f2..7f48d95d 100644
--- a/data/languages/swedish.txt
+++ b/data/languages/swedish.txt
@@ -1,3 +1,4 @@
+
 ##### translated strings #####
 
 %d Bytes
@@ -144,6 +145,9 @@ Delete demo
 Demo details
 == Demoinformation
 
+Demofile: %s
+== Demofil: %s
+
 Demos
 == Demon
 
@@ -387,9 +391,15 @@ Pistol
 Play
 == Spela
 
+Play background music
+== Aktivera bakgrundsmusik
+
 Player
 == Spelare
 
+Player country:
+== Land
+
 Player options
 == Spelaralternativ
 
@@ -537,6 +547,12 @@ Sound volume
 Spectate
 == Åskåda
 
+Spectate next
+== Se på nästa
+
+Spectate previous
+== Se på föregående
+
 Spectator mode
 == Åskådarläge
 
@@ -552,6 +568,9 @@ Standard map
 Stop record
 == Sluta spela in
 
+Strict gametype filter
+== Strikt speltypsfilter
+
 Sudden Death
 == Plötslig död
 
@@ -654,23 +673,7 @@ Your skin
 no limit
 == Ingen gräns
 
-Demofile: %s
-== Demofil: %s
-
-Play background music
-== Aktivera bakgrundsmusik
-
-Player country:
-== Land
-
-Spectate next
-== Se på nästa
-
-Spectate previous
-== Se på föregående
-
-Strict gametype filter
-== Strikt speltypsfilter
+##### needs translation #####
 
 ##### old translations #####
 
diff --git a/data/languages/ukrainian.txt b/data/languages/ukrainian.txt
index 9e696f51..93566829 100644
--- a/data/languages/ukrainian.txt
+++ b/data/languages/ukrainian.txt
@@ -50,7 +50,7 @@ Chat
 == Чат
 
 Close
-== Закрити
+== Зачинити
 
 Compatible version
 == Сумісна версія
@@ -86,10 +86,10 @@ Demos
 == Демо
 
 Disconnect
-== # Відключитись
+== Від'єднатись
 
 Disconnected
-== Відключено
+== Від'єднанно
 
 Display Modes
 == Режими дисплея
@@ -155,7 +155,7 @@ Game type
 == Тип гри
 
 Game types:
-== Тип гри:
+== Типи гри:
 
 General
 == Основні
@@ -164,7 +164,7 @@ Graphics
 == Графіка
 
 Grenade
-== Граната
+== Ракетниця
 
 Hammer
 == Молоток
@@ -215,7 +215,7 @@ Lht.
 == Яскравість
 
 Loading
-== Завантиження
+== Завантаження
 
 MOTD
 == MOTD
@@ -245,7 +245,7 @@ Mute when not active
 == Глушити звуки, коли гра неактивна
 
 Name
-== Імя
+== Ім'я
 
 News
 == Новини
@@ -332,7 +332,7 @@ Remote console
 == Консоль сервера
 
 Reset filter
-== Сикнути фільтри
+== Скинути фільтри
 
 Reset to defaults
 == Скинути налаштування
diff --git a/other/sdl/vc2005libs/SDL.dll b/other/sdl/vc2005libs/SDL.dll
index 628cdfcf..429ae545 100644
--- a/other/sdl/vc2005libs/SDL.dll
+++ b/other/sdl/vc2005libs/SDL.dll
Binary files differdiff --git a/other/sdl/vc2005libs/SDL.lib b/other/sdl/vc2005libs/SDL.lib
index 5b3f17c5..f4e860f8 100644
--- a/other/sdl/vc2005libs/SDL.lib
+++ b/other/sdl/vc2005libs/SDL.lib
Binary files differdiff --git a/other/sdl/vc2005libs/SDLmain.lib b/other/sdl/vc2005libs/SDLmain.lib
index 945b9ad8..825c03b9 100644
--- a/other/sdl/vc2005libs/SDLmain.lib
+++ b/other/sdl/vc2005libs/SDLmain.lib
Binary files differdiff --git a/scripts/cmd5.py b/scripts/cmd5.py
index a06d45a7..9b4804c7 100644
--- a/scripts/cmd5.py
+++ b/scripts/cmd5.py
@@ -30,6 +30,6 @@ for filename in sys.argv[1:]:
 
 hash = hashlib.md5(f).hexdigest().lower()[16:]
 #TODO 0.7: improve nethash creation
-if hash == "5c1e637ffddf3a37":
+if hash == "63d6e69c6025feff":
 	hash = "626fce9a778df4d4"
 print('#define GAME_NETVERSION_HASH "%s"' % hash)
diff --git a/src/base/system.c b/src/base/system.c
index 01f0b398..466e3ca6 100644
--- a/src/base/system.c
+++ b/src/base/system.c
@@ -42,10 +42,6 @@
 	#include <fcntl.h>
 	#include <direct.h>
 	#include <errno.h>
-
-	#ifndef EWOULDBLOCK
-		#define EWOULDBLOCK WSAEWOULDBLOCK
-	#endif
 #else
 	#error NOT IMPLEMENTED
 #endif
@@ -823,8 +819,6 @@ static int priv_net_close_all_sockets(NETSOCKET sock)
 static int priv_net_create_socket(int domain, int type, struct sockaddr *addr, int sockaddrlen)
 {
 	int sock, e;
-	unsigned long mode = 1;
-	int broadcast = 1;
 
 	/* create socket */
 	sock = socket(domain, type, 0);
@@ -852,16 +846,6 @@ static int priv_net_create_socket(int domain, int type, struct sockaddr *addr, i
 		return -1;
 	}
 
-	/* set non-blocking */
-#if defined(CONF_FAMILY_WINDOWS)
-	ioctlsocket(sock, FIONBIO, &mode);
-#else
-	ioctl(sock, FIONBIO, &mode);
-#endif
-
-	/* set boardcast */
-	setsockopt(sock, SOL_SOCKET, SO_BROADCAST, (const char*)&broadcast, sizeof(broadcast));
-
 	/* return the newly created socket */
 	return sock;
 }
@@ -870,6 +854,7 @@ NETSOCKET net_udp_create(NETADDR bindaddr)
 {
 	NETSOCKET sock = invalid_socket;
 	NETADDR tmpbindaddr = bindaddr;
+	int broadcast = 1;
 
 	if(bindaddr.type&NETTYPE_IPV4)
 	{
@@ -885,6 +870,12 @@ NETSOCKET net_udp_create(NETADDR bindaddr)
 			sock.type |= NETTYPE_IPV4;
 			sock.ipv4sock = socket;
 		}
+
+		/* set non-blocking */
+		net_set_non_blocking(sock);
+
+		/* set boardcast */
+		setsockopt(socket, SOL_SOCKET, SO_BROADCAST, (const char*)&broadcast, sizeof(broadcast));
 	}
 
 	if(bindaddr.type&NETTYPE_IPV6)
@@ -901,6 +892,12 @@ NETSOCKET net_udp_create(NETADDR bindaddr)
 			sock.type |= NETTYPE_IPV6;
 			sock.ipv6sock = socket;
 		}
+
+		/* set non-blocking */
+		net_set_non_blocking(sock);
+
+		/* set boardcast */
+		setsockopt(socket, SOL_SOCKET, SO_BROADCAST, (const char*)&broadcast, sizeof(broadcast));
 	}
 
 	/* return */
@@ -1010,32 +1007,48 @@ int net_udp_close(NETSOCKET sock)
 	return priv_net_close_all_sockets(sock);
 }
 
-// TODO: make TCP stuff work again
-NETSOCKET net_tcp_create(const NETADDR *a)
+NETSOCKET net_tcp_create(NETADDR bindaddr)
 {
-	/* TODO: IPv6 support */
 	NETSOCKET sock = invalid_socket;
+	NETADDR tmpbindaddr = bindaddr;
 
-	if(a->type&NETTYPE_IPV4)
+	if(bindaddr.type&NETTYPE_IPV4)
 	{
 		struct sockaddr_in addr;
+		int socket = -1;
+
+		/* bind, we should check for error */
+		tmpbindaddr.type = NETTYPE_IPV4;
+		netaddr_to_sockaddr_in(&tmpbindaddr, &addr);
+		socket = priv_net_create_socket(AF_INET, SOCK_STREAM, (struct sockaddr *)&addr, sizeof(addr));
+		if(socket >= 0)
+		{
+			sock.type |= NETTYPE_IPV4;
+			sock.ipv4sock = socket;
+		}
+	}
 
-		/* create socket */
-		sock.type |= NETTYPE_IPV4;
-		sock.ipv4sock = socket(AF_INET, SOCK_STREAM, 0);
-		if(sock.ipv4sock < 0)
-			return invalid_socket;
+	if(bindaddr.type&NETTYPE_IPV6)
+	{
+		struct sockaddr_in6 addr;
+		int socket = -1;
 
 		/* bind, we should check for error */
-		netaddr_to_sockaddr_in(a, &addr);
-		bind(sock.ipv4sock, (struct sockaddr *)&addr, sizeof(addr));
+		tmpbindaddr.type = NETTYPE_IPV6;
+		netaddr_to_sockaddr_in6(&tmpbindaddr, &addr);
+		socket = priv_net_create_socket(AF_INET6, SOCK_STREAM, (struct sockaddr *)&addr, sizeof(addr));
+		if(socket >= 0)
+		{
+			sock.type |= NETTYPE_IPV6;
+			sock.ipv6sock = socket;
+		}
 	}
 
 	/* return */
 	return sock;
 }
 
-int net_tcp_set_non_blocking(NETSOCKET sock)
+int net_set_non_blocking(NETSOCKET sock)
 {
 	unsigned long mode = 1;
 	if(sock.ipv4sock >= 0)
@@ -1059,7 +1072,7 @@ int net_tcp_set_non_blocking(NETSOCKET sock)
 	return 0;
 }
 
-int net_tcp_set_blocking(NETSOCKET sock)
+int net_set_blocking(NETSOCKET sock)
 {
 	unsigned long mode = 0;
 	if(sock.ipv4sock >= 0)
@@ -1085,30 +1098,31 @@ int net_tcp_set_blocking(NETSOCKET sock)
 
 int net_tcp_listen(NETSOCKET sock, int backlog)
 {
+	int err = -1;
 	if(sock.ipv4sock >= 0)
-		listen(sock.ipv4sock, backlog);
+		err = listen(sock.ipv4sock, backlog);
 	if(sock.ipv6sock >= 0)
-		listen(sock.ipv6sock, backlog);
-	return 0;
+		err = listen(sock.ipv6sock, backlog);
+	return err;
 }
 
 int net_tcp_accept(NETSOCKET sock, NETSOCKET *new_sock, NETADDR *a)
 {
 	int s;
 	socklen_t sockaddr_len;
-	struct sockaddr addr;
 
 	*new_sock = invalid_socket;
 
-	sockaddr_len = sizeof(addr);
-
 	if(sock.ipv4sock >= 0)
 	{
-		s = accept(sock.ipv4sock, &addr, &sockaddr_len);
+		struct sockaddr_in addr;
+		sockaddr_len = sizeof(addr);
 
+		s = accept(sock.ipv4sock, (struct sockaddr *)&addr, &sockaddr_len);
+		
 		if (s != -1)
 		{
-			sockaddr_to_netaddr(&addr, a);
+			sockaddr_to_netaddr((const struct sockaddr *)&addr, a);
 			new_sock->type = NETTYPE_IPV4;
 			new_sock->ipv4sock = s;
 			return s;
@@ -1117,55 +1131,74 @@ int net_tcp_accept(NETSOCKET sock, NETSOCKET *new_sock, NETADDR *a)
 
 	if(sock.ipv6sock >= 0)
 	{
-		s = accept(sock.ipv6sock, &addr, &sockaddr_len);
+		struct sockaddr_in6 addr;
+		sockaddr_len = sizeof(addr);
 
+		s = accept(sock.ipv6sock, (struct sockaddr *)&addr, &sockaddr_len);
+		
 		if (s != -1)
 		{
-			sockaddr_to_netaddr(&addr, a);
+			sockaddr_to_netaddr((const struct sockaddr *)&addr, a);
 			new_sock->type = NETTYPE_IPV6;
 			new_sock->ipv6sock = s;
 			return s;
 		}
 	}
 
-	return 0;
+	return -1;
 }
 
 int net_tcp_connect(NETSOCKET sock, const NETADDR *a)
 {
-	/*struct sockaddr addr;
-	netaddr_to_sockaddr(a, &addr);
-	return connect(sock, &addr, sizeof(addr));
-	*/
-	return 0;
+	if(a->type&NETTYPE_IPV4)
+	{
+		struct sockaddr_in addr;
+		netaddr_to_sockaddr_in(a, &addr);
+		return connect(sock.ipv4sock, (struct sockaddr *)&addr, sizeof(addr));
+	}
+
+	if(a->type&NETTYPE_IPV6)
+	{
+		struct sockaddr_in6 addr;
+		netaddr_to_sockaddr_in6(a, &addr);
+		return connect(sock.ipv6sock, (struct sockaddr *)&addr, sizeof(addr));
+	}
+
+	return -1;
 }
 
-int net_tcp_connect_non_blocking(NETSOCKET sock, const NETADDR *a)
+int net_tcp_connect_non_blocking(NETSOCKET sock, NETADDR bindaddr)
 {
-	/* struct sockaddr addr; */
 	int res = 0;
 
-	/*
-	netaddr_to_sockaddr(a, &addr);
-	net_tcp_set_non_blocking(sock);
-	res = connect(sock, &addr, sizeof(addr));
-	net_tcp_set_blocking(sock);
-	*/
+	net_set_non_blocking(sock);
+	res = net_tcp_connect(sock, &bindaddr);
+	net_set_blocking(sock);
 
 	return res;
 }
 
 int net_tcp_send(NETSOCKET sock, const void *data, int size)
 {
-	int bytes = 0;
-	/* bytes = send((int)sock, (const char*)data, size, 0); */
+	int bytes = -1;
+
+	if(sock.ipv4sock >= 0)
+		bytes = send((int)sock.ipv4sock, (const char*)data, size, 0);
+	if(sock.ipv6sock >= 0)
+		bytes = send((int)sock.ipv6sock, (const char*)data, size, 0);
+		
 	return bytes;
 }
 
 int net_tcp_recv(NETSOCKET sock, void *data, int maxsize)
 {
-	int bytes = 0;
-	/* bytes = recv((int)sock, (char*)data, maxsize, 0); */
+	int bytes = -1;
+
+	if(sock.ipv4sock >= 0)
+		bytes = recv((int)sock.ipv4sock, (char*)data, maxsize, 0);
+	if(sock.ipv6sock >= 0)
+		bytes = recv((int)sock.ipv6sock, (char*)data, maxsize, 0);
+		
 	return bytes;
 }
 
@@ -1176,12 +1209,20 @@ int net_tcp_close(NETSOCKET sock)
 
 int net_errno()
 {
+#if defined(CONF_FAMILY_WINDOWS)
+	return WSAGetLastError();
+#else
 	return errno;
+#endif
 }
 
 int net_would_block()
 {
+#if defined(CONF_FAMILY_WINDOWS)
+	return net_errno() == WSAEWOULDBLOCK;
+#else
 	return net_errno() == EWOULDBLOCK;
+#endif
 }
 
 int net_init()
diff --git a/src/base/system.h b/src/base/system.h
index de579076..aaa5b43f 100644
--- a/src/base/system.h
+++ b/src/base/system.h
@@ -591,7 +591,7 @@ int net_udp_close(NETSOCKET sock);
 	Returns:
 		On success it returns an handle to the socket. On failure it returns NETSOCKET_INVALID.
 */
-NETSOCKET net_tcp_create(const NETADDR *a);
+NETSOCKET net_tcp_create(NETADDR bindaddr);
 
 /*
 	Function: net_tcp_listen
@@ -1094,21 +1094,21 @@ int fs_rename(const char *oldname, const char *newname);
 
 	DOCTODO: serp
 */
-int net_tcp_connect_non_blocking(NETSOCKET sock, const NETADDR *a);
+int net_tcp_connect_non_blocking(NETSOCKET sock, NETADDR bindaddr);
 
 /*
-	Function: net_tcp_set_non_blocking
+	Function: net_set_non_blocking
 
 	DOCTODO: serp
 */
-int net_tcp_set_non_blocking(NETSOCKET sock);
+int net_set_non_blocking(NETSOCKET sock);
 
 /*
-	Function: net_tcp_set_non_blocking
+	Function: net_set_non_blocking
 
 	DOCTODO: serp
 */
-int net_tcp_set_blocking(NETSOCKET sock);
+int net_set_blocking(NETSOCKET sock);
 
 /*
 	Function: net_errno
diff --git a/src/engine/client.h b/src/engine/client.h
index 65ab761e..966e8f61 100644
--- a/src/engine/client.h
+++ b/src/engine/client.h
@@ -95,6 +95,7 @@ public:
 	// remote console
 	virtual void RconAuth(const char *pUsername, const char *pPassword) = 0;
 	virtual bool RconAuthed() = 0;
+	virtual bool UseTempRconCommands() = 0;
 	virtual void Rcon(const char *pLine) = 0;
 
 	// server info
diff --git a/src/engine/client/client.cpp b/src/engine/client/client.cpp
index 90cb2011..bec7d4d6 100644
--- a/src/engine/client/client.cpp
+++ b/src/engine/client/client.cpp
@@ -1,5 +1,6 @@
 /* (c) Magnus Auvinen. See licence.txt in the root of the distribution for more information. */
 /* If you are missing that file, acquire a complete release at teeworlds.com.                */
+#include <new>
 
 #include <stdlib.h> // qsort
 #include <stdarg.h>
@@ -26,6 +27,7 @@
 #include <engine/shared/compression.h>
 #include <engine/shared/datafile.h>
 #include <engine/shared/demo.h>
+#include <engine/shared/filecollection.h>
 #include <engine/shared/mapchecker.h>
 #include <engine/shared/network.h>
 #include <engine/shared/packer.h>
@@ -231,185 +233,6 @@ void CSmoothTime::Update(CGraph *pGraph, int64 Target, int TimeLeft, int AdjustD
 }
 
 
-bool CFileCollection::IsFilenameValid(const char *pFilename)
-{
-	if(str_length(pFilename) != m_FileDescLength+TIMESTAMP_LENGTH+m_FileExtLength ||
-		str_comp_num(pFilename, m_aFileDesc, m_FileDescLength) ||
-		str_comp(pFilename+m_FileDescLength+TIMESTAMP_LENGTH, m_aFileExt))
-		return false;
-
-	pFilename += m_FileDescLength;
-	if(pFilename[0] == '_' &&
-		pFilename[1] >= '0' && pFilename[1] <= '9' &&
-		pFilename[2] >= '0' && pFilename[2] <= '9' &&
-		pFilename[3] >= '0' && pFilename[3] <= '9' &&
-		pFilename[4] >= '0' && pFilename[4] <= '9' &&
-		pFilename[5] == '-' &&
-		pFilename[6] >= '0' && pFilename[6] <= '9' &&
-		pFilename[7] >= '0' && pFilename[7] <= '9' &&
-		pFilename[8] == '-' &&
-		pFilename[9] >= '0' && pFilename[9] <= '9' &&
-		pFilename[10] >= '0' && pFilename[10] <= '9' &&
-		pFilename[11] == '_' &&
-		pFilename[12] >= '0' && pFilename[12] <= '9' &&
-		pFilename[13] >= '0' && pFilename[13] <= '9' &&
-		pFilename[14] == '-' &&
-		pFilename[15] >= '0' && pFilename[15] <= '9' &&
-		pFilename[16] >= '0' && pFilename[16] <= '9' &&
-		pFilename[17] == '-' &&
-		pFilename[18] >= '0' && pFilename[18] <= '9' &&
-		pFilename[19] >= '0' && pFilename[19] <= '9')
-		return true;
-
-	return false;
-}
-
-int64 CFileCollection::ExtractTimestamp(const char *pTimestring)
-{
-	int64 Timestamp = pTimestring[0]-'0'; Timestamp <<= 4;
-	Timestamp += pTimestring[1]-'0'; Timestamp <<= 4;
-	Timestamp += pTimestring[2]-'0'; Timestamp <<= 4;
-	Timestamp += pTimestring[3]-'0'; Timestamp <<= 4;
-	Timestamp += pTimestring[5]-'0'; Timestamp <<= 4;
-	Timestamp += pTimestring[6]-'0'; Timestamp <<= 4;
-	Timestamp += pTimestring[8]-'0'; Timestamp <<= 4;
-	Timestamp += pTimestring[9]-'0'; Timestamp <<= 4;
-	Timestamp += pTimestring[11]-'0'; Timestamp <<= 4;
-	Timestamp += pTimestring[12]-'0'; Timestamp <<= 4;
-	Timestamp += pTimestring[14]-'0'; Timestamp <<= 4;
-	Timestamp += pTimestring[15]-'0'; Timestamp <<= 4;
-	Timestamp += pTimestring[17]-'0'; Timestamp <<= 4;
-	Timestamp += pTimestring[18]-'0';
-
-	return Timestamp;
-}
-
-void CFileCollection::BuildTimestring(int64 Timestamp, char *pTimestring)
-{
-	pTimestring[19] = 0;
-	pTimestring[18] = (Timestamp&0xF)+'0'; Timestamp >>= 4;
-	pTimestring[17] = (Timestamp&0xF)+'0'; Timestamp >>= 4;
-	pTimestring[16] = '-';
-	pTimestring[15] = (Timestamp&0xF)+'0'; Timestamp >>= 4;
-	pTimestring[14] = (Timestamp&0xF)+'0'; Timestamp >>= 4;
-	pTimestring[13] = '-';
-	pTimestring[12] = (Timestamp&0xF)+'0'; Timestamp >>= 4;
-	pTimestring[11] = (Timestamp&0xF)+'0'; Timestamp >>= 4;
-	pTimestring[10] = '_';
-	pTimestring[9] = (Timestamp&0xF)+'0'; Timestamp >>= 4;
-	pTimestring[8] = (Timestamp&0xF)+'0'; Timestamp >>= 4;
-	pTimestring[7] = '-';
-	pTimestring[6] = (Timestamp&0xF)+'0'; Timestamp >>= 4;
-	pTimestring[5] = (Timestamp&0xF)+'0'; Timestamp >>= 4;
-	pTimestring[4] = '-';
-	pTimestring[3] = (Timestamp&0xF)+'0'; Timestamp >>= 4;
-	pTimestring[2] = (Timestamp&0xF)+'0'; Timestamp >>= 4;
-	pTimestring[1] = (Timestamp&0xF)+'0'; Timestamp >>= 4;
-	pTimestring[0] = (Timestamp&0xF)+'0';
-}
-
-void CFileCollection::Init(IStorage *pStorage, const char *pPath, const char *pFileDesc, const char *pFileExt, int MaxEntries)
-{
-	mem_zero(m_aTimestamps, sizeof(m_aTimestamps));
-	m_NumTimestamps = 0;
-	m_MaxEntries = clamp(MaxEntries, 1, static_cast<int>(MAX_ENTRIES));
-	str_copy(m_aFileDesc, pFileDesc, sizeof(m_aFileDesc));
-	m_FileDescLength = str_length(m_aFileDesc);
-	str_copy(m_aFileExt, pFileExt, sizeof(m_aFileExt));
-	m_FileExtLength = str_length(m_aFileExt);
-	str_copy(m_aPath, pPath, sizeof(m_aPath));
-	m_pStorage = pStorage;
-
-	m_pStorage->ListDirectory(IStorage::TYPE_SAVE, m_aPath, FilelistCallback, this);
-}
-
-void CFileCollection::AddEntry(int64 Timestamp)
-{
-	if(m_NumTimestamps == 0)
-	{
-		// empty list
-		m_aTimestamps[m_NumTimestamps++] = Timestamp;
-	}
-	else
-	{
-		// remove old file
-		if(m_NumTimestamps == m_MaxEntries)
-		{
-			char aBuf[512];
-			char aTimestring[TIMESTAMP_LENGTH];
-			BuildTimestring(m_aTimestamps[0], aTimestring);
-			str_format(aBuf, sizeof(aBuf), "%s/%s_%s%s", m_aPath, m_aFileDesc, aTimestring, m_aFileExt);
-			m_pStorage->RemoveFile(aBuf, IStorage::TYPE_SAVE);
-		}
-
-		// add entry to the sorted list
-		if(m_aTimestamps[0] > Timestamp)
-		{
-			// first entry
-			if(m_NumTimestamps < m_MaxEntries)
-			{
-				mem_move(m_aTimestamps+1, m_aTimestamps, m_NumTimestamps*sizeof(int64));
-				m_aTimestamps[0] = Timestamp;
-				++m_NumTimestamps;
-			}
-		}
-		else if(m_aTimestamps[m_NumTimestamps-1] <= Timestamp)
-		{
-			// last entry
-			if(m_NumTimestamps == m_MaxEntries)
-			{
-				mem_move(m_aTimestamps, m_aTimestamps+1, (m_NumTimestamps-1)*sizeof(int64));
-				m_aTimestamps[m_NumTimestamps-1] = Timestamp;
-			}
-			else
-				m_aTimestamps[m_NumTimestamps++] = Timestamp;
-		}
-		else
-		{
-			// middle entry
-			int Left = 0, Right = m_NumTimestamps-1;
-			while(Right-Left > 1)
-			{
-				int Mid = (Left+Right)/2;
-				if(m_aTimestamps[Mid] > Timestamp)
-					Right = Mid;
-				else
-					Left = Mid;
-			}
-
-			if(m_NumTimestamps == m_MaxEntries)
-			{
-				mem_move(m_aTimestamps, m_aTimestamps+1, (Right-1)*sizeof(int64));
-				m_aTimestamps[Right-1] = Timestamp;
-			}
-			else
-			{
-				mem_move(m_aTimestamps+Right+1, m_aTimestamps+Right, (m_NumTimestamps-Right)*sizeof(int64));
-				m_aTimestamps[Right] = Timestamp;
-				++m_NumTimestamps;
-			}
-		}
-	}
-}
-
-int CFileCollection::FilelistCallback(const char *pFilename, int IsDir, int StorageType, void *pUser)
-{
-	CFileCollection *pThis = static_cast<CFileCollection *>(pUser);
-
-	// check for valid file name format
-	if(IsDir || !pThis->IsFilenameValid(pFilename))
-		return 0;
-
-	// extract the timestamp
-	int64 Timestamp = pThis->ExtractTimestamp(pFilename+pThis->m_FileDescLength+1);
-
-	// add the entry
-	pThis->AddEntry(Timestamp);
-
-	return 0;
-}
-
-
 CClient::CClient() : m_DemoPlayer(&m_SnapshotDelta), m_DemoRecorder(&m_SnapshotDelta)
 {
 	m_pEditor = 0;
@@ -467,6 +290,7 @@ CClient::CClient() : m_DemoPlayer(&m_SnapshotDelta), m_DemoRecorder(&m_SnapshotD
 	m_aServerAddressStr[0] = 0;
 
 	mem_zero(m_aSnapshots, sizeof(m_aSnapshots));
+	m_SnapshotStorage.Init();
 	m_RecivedSnapshots = 0;
 
 	m_VersionInfo.m_State = CVersionInfo::STATE_INIT;
@@ -536,11 +360,6 @@ void CClient::SendReady()
 	SendMsgEx(&Msg, MSGFLAG_VITAL|MSGFLAG_FLUSH);
 }
 
-bool CClient::RconAuthed()
-{
-	return m_RconAuthed;
-}
-
 void CClient::RconAuth(const char *pName, const char *pPassword)
 {
 	if(RconAuthed())
@@ -549,6 +368,7 @@ void CClient::RconAuth(const char *pName, const char *pPassword)
 	CMsgPacker Msg(NETMSG_RCON_AUTH);
 	Msg.AddString(pName, 32);
 	Msg.AddString(pPassword, 32);
+	Msg.AddInt(1);
 	SendMsgEx(&Msg, MSGFLAG_VITAL);
 }
 
@@ -693,12 +513,12 @@ void CClient::Connect(const char *pAddress)
 
 	ServerInfoRequest();
 
-	if(net_host_lookup(m_aServerAddressStr, &m_ServerAddress, NETTYPE_ALL) != 0)
+	if(net_host_lookup(m_aServerAddressStr, &m_ServerAddress, m_NetClient.NetType()) != 0)
 	{
 		char aBufMsg[256];
 		str_format(aBufMsg, sizeof(aBufMsg), "could not find the address of %s, connecting to localhost", aBuf);
 		m_pConsole->Print(IConsole::OUTPUT_LEVEL_STANDARD, "client", aBufMsg);
-		net_host_lookup("localhost", &m_ServerAddress, NETTYPE_ALL);
+		net_host_lookup("localhost", &m_ServerAddress, m_NetClient.NetType());
 	}
 
 	m_RconAuthed = 0;
@@ -726,6 +546,7 @@ void CClient::DisconnectWithReason(const char *pReason)
 
 	//
 	m_RconAuthed = 0;
+	m_pConsole->DeregisterTempAll();
 	m_NetClient.Disconnect(pReason);
 	SetState(IClient::STATE_OFFLINE);
 	m_pMap->Unload();
@@ -1313,11 +1134,28 @@ void CClient::ProcessServerPacket(CNetChunk *pPacket)
 			CMsgPacker Msg(NETMSG_PING_REPLY);
 			SendMsgEx(&Msg, 0);
 		}
+		else if(Msg == NETMSG_RCON_CMD_ADD)
+		{
+			const char *pName = Unpacker.GetString(CUnpacker::SANITIZE_CC);
+			const char *pHelp = Unpacker.GetString(CUnpacker::SANITIZE_CC);
+			const char *pParams = Unpacker.GetString(CUnpacker::SANITIZE_CC);
+			if(Unpacker.Error() == 0)
+				m_pConsole->RegisterTemp(pName, pParams, CFGFLAG_SERVER, pHelp);
+		}
+		else if(Msg == NETMSG_RCON_CMD_REM)
+		{
+			const char *pName = Unpacker.GetString(CUnpacker::SANITIZE_CC);
+			if(Unpacker.Error() == 0)
+				m_pConsole->DeregisterTemp(pName);
+		}
 		else if(Msg == NETMSG_RCON_AUTH_STATUS)
 		{
 			int Result = Unpacker.GetInt();
 			if(Unpacker.Error() == 0)
 				m_RconAuthed = Result;
+			m_UseTempRconCommands = Unpacker.GetInt();
+			if(Unpacker.Error() != 0)
+				m_UseTempRconCommands = 0;
 		}
 		else if(Msg == NETMSG_RCON_LINE)
 		{
@@ -1799,7 +1637,7 @@ void CClient::VersionUpdate()
 {
 	if(m_VersionInfo.m_State == CVersionInfo::STATE_INIT)
 	{
-		Engine()->HostLookup(&m_VersionInfo.m_VersionServeraddr, g_Config.m_ClVersionServer, m_BindAddr.type);
+		Engine()->HostLookup(&m_VersionInfo.m_VersionServeraddr, g_Config.m_ClVersionServer, m_NetClient.NetType());
 		m_VersionInfo.m_State = CVersionInfo::STATE_START;
 	}
 	else if(m_VersionInfo.m_State == CVersionInfo::STATE_START)
@@ -1881,7 +1719,7 @@ void CClient::Run()
 	Input()->Init();
 
 	// start refreshing addresses while we load
-	MasterServer()->RefreshAddresses(m_BindAddr.type);
+	MasterServer()->RefreshAddresses(m_NetClient.NetType());
 
 	// init the editor
 	m_pEditor->Init();
@@ -2328,7 +2166,12 @@ void CClient::RegisterCommands()
 	m_pConsole->Chain("br_filter_serveraddress", ConchainServerBrowserUpdate, this);
 }
 
-static CClient m_Client;
+static CClient *CreateClient()
+{
+	CClient *pClient = static_cast<CClient *>(mem_alloc(sizeof(CClient), 1));
+	mem_zero(pClient, sizeof(CClient));
+	return new(pClient) CClient;
+}
 
 /*
 	Server Time
@@ -2359,9 +2202,10 @@ int main(int argc, const char **argv) // ignore_convention
 	}
 #endif
 
+	CClient *pClient = CreateClient();
 	IKernel *pKernel = IKernel::Create();
-	pKernel->RegisterInterface(&m_Client);
-	m_Client.RegisterInterfaces();
+	pKernel->RegisterInterface(pClient);
+	pClient->RegisterInterfaces();
 
 	// create the components
 	IEngine *pEngine = CreateEngine("Teeworlds");
@@ -2414,12 +2258,12 @@ int main(int argc, const char **argv) // ignore_convention
 	pEngineMasterServer->Load();
 
 	// register all console commands
-	m_Client.RegisterCommands();
+	pClient->RegisterCommands();
 
 	pKernel->RequestInterface<IGameClient>()->OnConsoleInit();
 
 	// init client's interfaces
-	m_Client.InitInterfaces();
+	pClient->InitInterfaces();
 
 	// execute config file
 	pConsole->ExecuteFile("settings.cfg");
@@ -2434,11 +2278,11 @@ int main(int argc, const char **argv) // ignore_convention
 	// restore empty config strings to their defaults
 	pConfig->RestoreStrings();
 
-	m_Client.Engine()->InitLogfile();
+	pClient->Engine()->InitLogfile();
 
 	// run the client
 	dbg_msg("client", "starting...");
-	m_Client.Run();
+	pClient->Run();
 
 	// write down the config and quit
 	pConfig->Save();
diff --git a/src/engine/client/client.h b/src/engine/client/client.h
index ddcd1167..1504a4e4 100644
--- a/src/engine/client/client.h
+++ b/src/engine/client/client.h
@@ -51,36 +51,6 @@ public:
 };
 
 
-class CFileCollection
-{
-	enum
-	{
-		MAX_ENTRIES=1000,
-		TIMESTAMP_LENGTH=20,	// _YYYY-MM-DD_HH-MM-SS
-	};
-
-	int64 m_aTimestamps[MAX_ENTRIES];
-	int m_NumTimestamps;
-	int m_MaxEntries;
-	char m_aFileDesc[128];
-	int m_FileDescLength;
-	char m_aFileExt[32];
-	int m_FileExtLength;
-	char m_aPath[512];
-	IStorage *m_pStorage;
-
-	bool IsFilenameValid(const char *pFilename);
-	int64 ExtractTimestamp(const char *pTimestring);
-	void BuildTimestring(int64 Timestamp, char *pTimestring);
-
-public:
-	void Init(IStorage *pStorage, const char *pPath, const char *pFileDesc, const char *pFileExt, int MaxEntries);
-	void AddEntry(int64 Timestamp);
-
-	static int FilelistCallback(const char *pFilename, int IsDir, int StorageType, void *pUser);
-};
-
-
 class CClient : public IClient, public CDemoPlayer::IListner
 {
 	// needed interfaces
@@ -118,7 +88,6 @@ class CClient : public IClient, public CDemoPlayer::IListner
 	float m_FrameTimeHigh;
 	int m_Frames;
 	NETADDR m_ServerAddress;
-	NETADDR m_BindAddr;
 	int m_WindowMustRefocus;
 	int m_SnapCrcErrors;
 	bool m_AutoScreenshotRecycle;
@@ -129,6 +98,7 @@ class CClient : public IClient, public CDemoPlayer::IListner
 	int m_AckGameTick;
 	int m_CurrentRecvTick;
 	int m_RconAuthed;
+	int m_UseTempRconCommands;
 
 	// version-checking
 	char m_aVersionStr[10];
@@ -221,7 +191,8 @@ public:
 	void SendEnterGame();
 	void SendReady();
 
-	virtual bool RconAuthed();
+	virtual bool RconAuthed() { return m_RconAuthed != 0; }
+	virtual bool UseTempRconCommands() { return m_UseTempRconCommands != 0; }
 	void RconAuth(const char *pName, const char *pPassword);
 	virtual void Rcon(const char *pCmd);
 
diff --git a/src/engine/client/friends.cpp b/src/engine/client/friends.cpp
index 99f82b50..eca39edb 100644
--- a/src/engine/client/friends.cpp
+++ b/src/engine/client/friends.cpp
@@ -12,6 +12,7 @@
 CFriends::CFriends()
 {
 	mem_zero(m_aFriends, sizeof(m_aFriends));
+	m_NumFriends = 0;
 }
 
 void CFriends::ConAddFriend(IConsole::IResult *pResult, void *pUserData)
diff --git a/src/engine/client/graphics.cpp b/src/engine/client/graphics.cpp
index 76fd3400..d1f0b8a8 100644
--- a/src/engine/client/graphics.cpp
+++ b/src/engine/client/graphics.cpp
@@ -179,7 +179,16 @@ CGraphics_OpenGL::CGraphics_OpenGL()
 
 void CGraphics_OpenGL::ClipEnable(int x, int y, int w, int h)
 {
-	//if(no_gfx) return;
+	if(x < 0)
+		w += x;
+	if(y < 0)
+		h += y;
+
+	x = clamp(x, 0, ScreenWidth());
+	y = clamp(y, 0, ScreenHeight());
+	w = clamp(w, 0, ScreenWidth()-x);
+	h = clamp(h, 0, ScreenHeight()-y);
+
 	glScissor(x, ScreenHeight()-(y+h), w, h);
 	glEnable(GL_SCISSOR_TEST);
 }
diff --git a/src/engine/console.h b/src/engine/console.h
index f8ec67b0..0abf4ad2 100644
--- a/src/engine/console.h
+++ b/src/engine/console.h
@@ -10,11 +10,21 @@ class IConsole : public IInterface
 	MACRO_INTERFACE("console", 0)
 public:
 
+	//	TODO: rework/cleanup
 	enum
 	{
 		OUTPUT_LEVEL_STANDARD=0,
 		OUTPUT_LEVEL_ADDINFO,
-		OUTPUT_LEVEL_DEBUG
+		OUTPUT_LEVEL_DEBUG,
+
+		ACCESS_LEVEL_ADMIN=0,
+		ACCESS_LEVEL_MOD,
+
+		TEMPCMD_NAME_LENGTH=32,
+		TEMPCMD_HELP_LENGTH=96,
+		TEMPCMD_PARAMS_LENGTH=16,
+
+		MAX_PRINT_CB=4,
 	};
 
 	// TODO: rework this interface to reduce the amount of virtual calls
@@ -35,10 +45,18 @@ public:
 
 	class CCommandInfo
 	{
+	protected:
+		int m_AccessLevel;
 	public:
+		CCommandInfo() { m_AccessLevel = ACCESS_LEVEL_ADMIN; }
+		virtual ~CCommandInfo() {}
 		const char *m_pName;
 		const char *m_pHelp;
 		const char *m_pParams;
+
+		virtual const CCommandInfo *NextCommandInfo(int AccessLevel, int FlagMask) const = 0;
+
+		int GetAccessLevel() const { return m_AccessLevel; }
 	};
 
 	typedef void (*FPrintCallback)(const char *pStr, void *pUser);
@@ -46,12 +64,15 @@ public:
 	typedef void (*FCommandCallback)(IResult *pResult, void *pUserData);
 	typedef void (*FChainCommandCallback)(IResult *pResult, void *pUserData, FCommandCallback pfnCallback, void *pCallbackUserData);
 
-	virtual CCommandInfo *GetCommandInfo(const char *pName, int FlagMask) = 0;
-	virtual void PossibleCommands(const char *pStr, int FlagMask, FPossibleCallback pfnCallback, void *pUser) = 0;
+	virtual const CCommandInfo *FirstCommandInfo(int AccessLevel, int Flagmask) const = 0;
+	virtual const CCommandInfo *GetCommandInfo(const char *pName, int FlagMask, bool Temp) = 0;
+	virtual void PossibleCommands(const char *pStr, int FlagMask, bool Temp, FPossibleCallback pfnCallback, void *pUser) = 0;
 	virtual void ParseArguments(int NumArgs, const char **ppArguments) = 0;
 
-	virtual void Register(const char *pName, const char *pParams,
-		int Flags, FCommandCallback pfnFunc, void *pUser, const char *pHelp) = 0;
+	virtual void Register(const char *pName, const char *pParams, int Flags, FCommandCallback pfnFunc, void *pUser, const char *pHelp) = 0;
+	virtual void RegisterTemp(const char *pName, const char *pParams, int Flags, const char *pHelp) = 0;
+	virtual void DeregisterTemp(const char *pName) = 0;
+	virtual void DeregisterTempAll() = 0;
 	virtual void Chain(const char *pName, FChainCommandCallback pfnChainFunc, void *pUser) = 0;
 	virtual void StoreCommands(bool Store) = 0;
 
@@ -60,8 +81,11 @@ public:
 	virtual void ExecuteLineStroked(int Stroke, const char *pStr) = 0;
 	virtual void ExecuteFile(const char *pFilename) = 0;
 
-	virtual void RegisterPrintCallback(FPrintCallback pfnPrintCallback, void *pUserData) = 0;
+	virtual int RegisterPrintCallback(int OutputLevel, FPrintCallback pfnPrintCallback, void *pUserData) = 0;
+	virtual void SetPrintOutputLevel(int Index, int OutputLevel) = 0;
 	virtual void Print(int Level, const char *pFrom, const char *pStr) = 0;
+
+	virtual void SetAccessLevel(int AccessLevel) = 0;
 };
 
 extern IConsole *CreateConsole(int FlagMask);
diff --git a/src/engine/masterserver.h b/src/engine/masterserver.h
index 74a394dc..57433993 100644
--- a/src/engine/masterserver.h
+++ b/src/engine/masterserver.h
@@ -23,7 +23,6 @@ public:
 	virtual int RefreshAddresses(int Nettype) = 0;
 	virtual void Update() = 0;
 	virtual int IsRefreshing() = 0;
-	virtual void DumpServers() = 0;
 	virtual NETADDR GetAddr(int Index) = 0;
 	virtual const char *GetName(int Index) = 0;
 	virtual bool IsValid(int Index) = 0;
diff --git a/src/engine/server.h b/src/engine/server.h
index 28a97ecc..31134ca9 100644
--- a/src/engine/server.h
+++ b/src/engine/server.h
@@ -56,6 +56,8 @@ public:
 
 	virtual bool IsAuthed(int ClientID) = 0;
 	virtual void Kick(int ClientID, const char *pReason) = 0;
+
+	virtual void DemoRecorder_HandleAutoStart() = 0;
 };
 
 class IGameServer : public IInterface
diff --git a/src/engine/server/server.cpp b/src/engine/server/server.cpp
index 0e43e73f..193547cc 100644
--- a/src/engine/server/server.cpp
+++ b/src/engine/server/server.cpp
@@ -1,6 +1,7 @@
 /* (c) Magnus Auvinen. See licence.txt in the root of the distribution for more information. */
 /* If you are missing that file, acquire a complete release at teeworlds.com.                */
 
+#include <base/math.h>
 #include <base/system.h>
 
 #include <engine/config.h>
@@ -15,6 +16,8 @@
 #include <engine/shared/config.h>
 #include <engine/shared/datafile.h>
 #include <engine/shared/demo.h>
+#include <engine/shared/econ.h>
+#include <engine/shared/filecollection.h>
 #include <engine/shared/mapchecker.h>
 #include <engine/shared/network.h>
 #include <engine/shared/packer.h>
@@ -181,6 +184,7 @@ CServer::CServer() : m_DemoRecorder(&m_SnapshotDelta)
 	m_MapReload = 0;
 
 	m_RconClientID = -1;
+	m_RconAuthLevel = AUTHED_ADMIN;
 
 	Init();
 }
@@ -280,6 +284,11 @@ void CServer::Kick(int ClientID, const char *pReason)
 		Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "server", "you can't kick yourself");
  		return;
 	}
+	else if(m_aClients[ClientID].m_Authed > m_RconAuthLevel)
+	{
+		Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "server", "kick command denied");
+ 		return;
+	}
 
 	m_NetServer.Drop(ClientID, pReason);
 }
@@ -571,8 +580,9 @@ int CServer::NewClientCallback(int ClientID, void *pUser)
 	pThis->m_aClients[ClientID].m_aName[0] = 0;
 	pThis->m_aClients[ClientID].m_aClan[0] = 0;
 	pThis->m_aClients[ClientID].m_Country = -1;
-	pThis->m_aClients[ClientID].m_Authed = 0;
+	pThis->m_aClients[ClientID].m_Authed = AUTHED_NO;
 	pThis->m_aClients[ClientID].m_AuthTries = 0;
+	pThis->m_aClients[ClientID].m_pRconCmdToSend = 0;
 	pThis->m_aClients[ClientID].Reset();
 	return 0;
 }
@@ -596,8 +606,9 @@ int CServer::DelClientCallback(int ClientID, const char *pReason, void *pUser)
 	pThis->m_aClients[ClientID].m_aName[0] = 0;
 	pThis->m_aClients[ClientID].m_aClan[0] = 0;
 	pThis->m_aClients[ClientID].m_Country = -1;
-	pThis->m_aClients[ClientID].m_Authed = 0;
+	pThis->m_aClients[ClientID].m_Authed = AUTHED_NO;
 	pThis->m_aClients[ClientID].m_AuthTries = 0;
+	pThis->m_aClients[ClientID].m_pRconCmdToSend = 0;
 	pThis->m_aClients[ClientID].m_Snapshots.PurgeAll();
 	return 0;
 }
@@ -635,13 +646,44 @@ void CServer::SendRconLineAuthed(const char *pLine, void *pUser)
 
 	for(i = 0; i < MAX_CLIENTS; i++)
 	{
-		if(pThis->m_aClients[i].m_State != CClient::STATE_EMPTY && pThis->m_aClients[i].m_Authed)
+		if(pThis->m_aClients[i].m_State != CClient::STATE_EMPTY && pThis->m_aClients[i].m_Authed >= pThis->m_RconAuthLevel)
 			pThis->SendRconLine(i, pLine);
 	}
 
 	ReentryGuard--;
 }
 
+void CServer::SendRconCmdAdd(const IConsole::CCommandInfo *pCommandInfo, int ClientID)
+{
+	CMsgPacker Msg(NETMSG_RCON_CMD_ADD);
+	Msg.AddString(pCommandInfo->m_pName, IConsole::TEMPCMD_NAME_LENGTH);
+	Msg.AddString(pCommandInfo->m_pHelp, IConsole::TEMPCMD_HELP_LENGTH);
+	Msg.AddString(pCommandInfo->m_pParams, IConsole::TEMPCMD_PARAMS_LENGTH);
+	SendMsgEx(&Msg, MSGFLAG_VITAL, ClientID, true);
+}
+
+void CServer::SendRconCmdRem(const IConsole::CCommandInfo *pCommandInfo, int ClientID)
+{
+	CMsgPacker Msg(NETMSG_RCON_CMD_REM);
+	Msg.AddString(pCommandInfo->m_pName, 256);
+	SendMsgEx(&Msg, MSGFLAG_VITAL, ClientID, true);
+}
+
+void CServer::UpdateClientRconCommands()
+{
+	int ClientID = Tick() % MAX_CLIENTS;
+		
+	if(m_aClients[ClientID].m_State != CClient::STATE_EMPTY && m_aClients[ClientID].m_Authed)
+	{
+		int ConsoleAccessLevel = m_aClients[ClientID].m_Authed == AUTHED_ADMIN ? IConsole::ACCESS_LEVEL_ADMIN : IConsole::ACCESS_LEVEL_MOD;
+		for(int i = 0; i < MAX_RCONCMD_SEND && m_aClients[ClientID].m_pRconCmdToSend; ++i)
+		{
+			SendRconCmdAdd(m_aClients[ClientID].m_pRconCmdToSend, ClientID);
+			m_aClients[ClientID].m_pRconCmdToSend = m_aClients[ClientID].m_pRconCmdToSend->NextCommandInfo(ConsoleAccessLevel, CFGFLAG_SERVER);
+		}
+	}
+}
+
 void CServer::ProcessClientPacket(CNetChunk *pPacket)
 {
 	int ClientID = pPacket->m_ClientID;
@@ -813,8 +855,12 @@ void CServer::ProcessClientPacket(CNetChunk *pPacket)
 				str_format(aBuf, sizeof(aBuf), "ClientID=%d rcon='%s'", ClientID, pCmd);
 				Console()->Print(IConsole::OUTPUT_LEVEL_ADDINFO, "server", aBuf);
 				m_RconClientID = ClientID;
+				m_RconAuthLevel = m_aClients[ClientID].m_Authed;
+				Console()->SetAccessLevel(m_aClients[ClientID].m_Authed == AUTHED_ADMIN ? IConsole::ACCESS_LEVEL_ADMIN : IConsole::ACCESS_LEVEL_MOD);
 				Console()->ExecuteLine(pCmd);
+				Console()->SetAccessLevel(IConsole::ACCESS_LEVEL_ADMIN);
 				m_RconClientID = -1;
+				m_RconAuthLevel = AUTHED_ADMIN;
 			}
 		}
 		else if(Msg == NETMSG_RCON_AUTH)
@@ -825,20 +871,40 @@ void CServer::ProcessClientPacket(CNetChunk *pPacket)
 
 			if(Unpacker.Error() == 0)
 			{
-				if(g_Config.m_SvRconPassword[0] == 0)
+				if(g_Config.m_SvRconPassword[0] == 0 && g_Config.m_SvRconModPassword[0] == 0)
 				{
-					SendRconLine(ClientID, "No rcon password set on server. Set sv_rcon_password to enable the remote console.");
+					SendRconLine(ClientID, "No rcon password set on server. Set sv_rcon_password and/or sv_rcon_mod_password to enable the remote console.");
 				}
-				else if(str_comp(pPw, g_Config.m_SvRconPassword) == 0)
+				else if(g_Config.m_SvRconPassword[0] && str_comp(pPw, g_Config.m_SvRconPassword) == 0)
 				{
 					CMsgPacker Msg(NETMSG_RCON_AUTH_STATUS);
-					Msg.AddInt(1);
+					Msg.AddInt(1);	//authed
+					Msg.AddInt(1);	//cmdlist
 					SendMsgEx(&Msg, MSGFLAG_VITAL, ClientID, true);
 
-					m_aClients[ClientID].m_Authed = 1;
-					SendRconLine(ClientID, "Authentication successful. Remote console access granted.");
+					m_aClients[ClientID].m_Authed = AUTHED_ADMIN;
+					int SendRconCmds = Unpacker.GetInt();
+					if(Unpacker.Error() == 0 && SendRconCmds)
+						m_aClients[ClientID].m_pRconCmdToSend = Console()->FirstCommandInfo(IConsole::ACCESS_LEVEL_ADMIN, CFGFLAG_SERVER);
+					SendRconLine(ClientID, "Admin authentication successful. Full remote console access granted.");
 					char aBuf[256];
-					str_format(aBuf, sizeof(aBuf), "ClientID=%d authed", ClientID);
+					str_format(aBuf, sizeof(aBuf), "ClientID=%d authed (admin)", ClientID);
+					Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "server", aBuf);
+				}
+				else if(g_Config.m_SvRconModPassword[0] && str_comp(pPw, g_Config.m_SvRconModPassword) == 0)
+				{
+					CMsgPacker Msg(NETMSG_RCON_AUTH_STATUS);
+					Msg.AddInt(1);	//authed
+					Msg.AddInt(1);	//cmdlist
+					SendMsgEx(&Msg, MSGFLAG_VITAL, ClientID, true);
+
+					m_aClients[ClientID].m_Authed = AUTHED_MOD;
+					int SendRconCmds = Unpacker.GetInt();
+					if(Unpacker.Error() == 0 && SendRconCmds)
+						m_aClients[ClientID].m_pRconCmdToSend = Console()->FirstCommandInfo(IConsole::ACCESS_LEVEL_MOD, CFGFLAG_SERVER);
+					SendRconLine(ClientID, "Moderator authentication successful. Limited remote console access granted.");
+					char aBuf[256];
+					str_format(aBuf, sizeof(aBuf), "ClientID=%d authed (moderator)", ClientID);
 					Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "server", aBuf);
 				}
 				else if(g_Config.m_SvRconMaxTries)
@@ -1020,6 +1086,8 @@ void CServer::PumpNetwork()
 		else
 			ProcessClientPacket(&Packet);
 	}
+
+	m_Econ.Update();
 }
 
 char *CServer::GetMapName()
@@ -1094,7 +1162,7 @@ int CServer::Run()
 	m_pStorage = Kernel()->RequestInterface<IStorage>();
 
 	//
-	Console()->RegisterPrintCallback(SendRconLineAuthed, this);
+	m_PrintCBIndex = Console()->RegisterPrintCallback(g_Config.m_ConsoleOutputLevel, SendRconLineAuthed, this);
 
 	// load map
 	if(!LoadMap(g_Config.m_SvMap))
@@ -1117,7 +1185,6 @@ int CServer::Run()
 		BindAddr.port = g_Config.m_SvPort;
 	}
 
-
 	if(!m_NetServer.Open(BindAddr, g_Config.m_SvMaxClients, g_Config.m_SvMaxClientsPerIP, 0))
 	{
 		dbg_msg("server", "couldn't open socket. port might already be in use");
@@ -1126,6 +1193,8 @@ int CServer::Run()
 
 	m_NetServer.SetCallbacks(NewClientCallback, DelClientCallback, this);
 
+	m_Econ.Init(Console());
+
 	char aBuf[256];
 	str_format(aBuf, sizeof(aBuf), "server name is '%s'", g_Config.m_SvName);
 	Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "server", aBuf);
@@ -1220,10 +1289,12 @@ int CServer::Run()
 			{
 				if(g_Config.m_SvHighBandwidth || (m_CurrentGameTick%2) == 0)
 					DoSnapshot();
+
+				UpdateClientRconCommands();
 			}
 
 			// master server stuff
-			m_Register.RegisterUpdate(BindAddr.type);
+			m_Register.RegisterUpdate(m_NetServer.NetType());
 
 			PumpNetwork();
 
@@ -1261,6 +1332,8 @@ int CServer::Run()
 	{
 		if(m_aClients[i].m_State != CClient::STATE_EMPTY)
 			m_NetServer.Drop(i, "Server shutdown");
+
+		m_Econ.Shutdown();
 	}
 
 	GameServer()->OnShutdown();
@@ -1292,7 +1365,7 @@ void CServer::ConBan(IConsole::IResult *pResult, void *pUser)
 	const char *pReason = "No reason given";
 
 	if(pResult->NumArguments() > 1)
-		Minutes = pResult->GetInteger(1);
+		Minutes = max(0, pResult->GetInteger(1));
 
 	if(pResult->NumArguments() > 2)
 		pReason = pResult->GetString(2);
@@ -1308,6 +1381,20 @@ void CServer::ConBan(IConsole::IResult *pResult, void *pUser)
 				pServer->Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "server", "you can't ban yourself");
 				return;
 			}
+
+			for(int i = 0; i < MAX_CLIENTS; ++i)
+			{
+				if(i == pServer->m_RconClientID)
+					continue;
+
+				AddrCheck = pServer->m_NetServer.ClientAddr(i);
+				AddrCheck.port = 0;
+				if(net_addr_comp(&Addr, &AddrCheck) == 0 && pServer->m_aClients[i].m_Authed > pServer->m_RconAuthLevel)
+				{
+					pServer->Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "server", "ban command denied");
+					return;
+				}
+			}
 		}
 		pServer->BanAdd(Addr, Minutes*60, pReason);
 	}
@@ -1325,6 +1412,11 @@ void CServer::ConBan(IConsole::IResult *pResult, void *pUser)
 			pServer->Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "server", "you can't ban yourself");
 			return;
 		}
+		else if(pServer->m_aClients[ClientID].m_Authed > pServer->m_RconAuthLevel)
+		{
+			pServer->Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "server", "ban command denied");
+			return;
+		}
 
 		Addr = pServer->m_NetServer.ClientAddr(ClientID);
 		pServer->BanAdd(Addr, Minutes*60, pReason);
@@ -1430,6 +1522,25 @@ void CServer::ConShutdown(IConsole::IResult *pResult, void *pUser)
 	((CServer *)pUser)->m_RunServer = 0;
 }
 
+void CServer::DemoRecorder_HandleAutoStart()
+{
+	if(g_Config.m_SvAutoDemoRecord)
+	{
+		m_DemoRecorder.Stop();
+		char aFilename[128];
+		char aDate[20];
+		str_timestamp(aDate, sizeof(aDate));
+		str_format(aFilename, sizeof(aFilename), "demos/%s_%s.demo", "auto/autorecord", aDate);
+		m_DemoRecorder.Start(Storage(), m_pConsole, aFilename, GameServer()->NetVersion(), m_aCurrentMap, m_CurrentMapCrc, "server");
+		if(g_Config.m_SvAutoDemoMax)
+		{
+			// clean up auto recorded demos
+			CFileCollection AutoDemos;
+			AutoDemos.Init(Storage(), "demos/server", "autorecord", ".demo", g_Config.m_SvAutoDemoMax);
+		}
+	}
+}
+
 void CServer::ConRecord(IConsole::IResult *pResult, void *pUser)
 {
 	CServer* pServer = (CServer *)pUser;
@@ -1470,26 +1581,67 @@ void CServer::ConchainMaxclientsperipUpdate(IConsole::IResult *pResult, void *pU
 		((CServer *)pUserData)->m_NetServer.SetMaxClientsPerIP(pResult->GetInteger(0));
 }
 
+void CServer::ConchainModCommandUpdate(IConsole::IResult *pResult, void *pUserData, IConsole::FCommandCallback pfnCallback, void *pCallbackUserData)
+{
+	if(pResult->NumArguments() == 2)
+	{
+		CServer *pThis = static_cast<CServer *>(pUserData);
+		const IConsole::CCommandInfo *pInfo = pThis->Console()->GetCommandInfo(pResult->GetString(0), CFGFLAG_SERVER, false);
+		int OldAccessLevel;
+		if(pInfo)
+			OldAccessLevel = pInfo->GetAccessLevel();
+		pfnCallback(pResult, pCallbackUserData);
+		if(pInfo && OldAccessLevel != pInfo->GetAccessLevel())
+		{
+			for(int i = 0; i < MAX_CLIENTS; ++i)
+			{
+				if(pThis->m_aClients[i].m_State == CServer::CClient::STATE_EMPTY || pThis->m_aClients[i].m_Authed != CServer::AUTHED_MOD ||
+					(pThis->m_aClients[i].m_pRconCmdToSend && str_comp(pResult->GetString(0), pThis->m_aClients[i].m_pRconCmdToSend->m_pName) >= 0))
+					continue;
+
+				if(OldAccessLevel == IConsole::ACCESS_LEVEL_ADMIN)
+					pThis->SendRconCmdAdd(pInfo, i);
+				else
+					pThis->SendRconCmdRem(pInfo, i);
+			}
+		}
+	}
+	else
+		pfnCallback(pResult, pCallbackUserData);
+}
+
+void CServer::ConchainConsoleOutputLevelUpdate(IConsole::IResult *pResult, void *pUserData, IConsole::FCommandCallback pfnCallback, void *pCallbackUserData)
+{
+	pfnCallback(pResult, pCallbackUserData);
+	if(pResult->NumArguments() == 1)
+	{
+		CServer *pThis = static_cast<CServer *>(pUserData);
+		pThis->Console()->SetPrintOutputLevel(pThis->m_PrintCBIndex, pResult->GetInteger(0));
+	}
+}
+
 void CServer::RegisterCommands()
 {
 	m_pConsole = Kernel()->RequestInterface<IConsole>();
 
-	Console()->Register("kick", "i?r", CFGFLAG_SERVER, ConKick, this, "");
-	Console()->Register("ban", "s?ir", CFGFLAG_SERVER|CFGFLAG_STORE, ConBan, this, "");
-	Console()->Register("unban", "s", CFGFLAG_SERVER|CFGFLAG_STORE, ConUnban, this, "");
-	Console()->Register("bans", "", CFGFLAG_SERVER|CFGFLAG_STORE, ConBans, this, "");
-	Console()->Register("status", "", CFGFLAG_SERVER, ConStatus, this, "");
-	Console()->Register("shutdown", "", CFGFLAG_SERVER, ConShutdown, this, "");
+	Console()->Register("kick", "i?r", CFGFLAG_SERVER, ConKick, this, "Kick player with specified id for any reason");
+	Console()->Register("ban", "s?ir", CFGFLAG_SERVER|CFGFLAG_STORE, ConBan, this, "Ban player with ip/id for x minutes for any reason");
+	Console()->Register("unban", "s", CFGFLAG_SERVER|CFGFLAG_STORE, ConUnban, this, "Unban ip");
+	Console()->Register("bans", "", CFGFLAG_SERVER|CFGFLAG_STORE, ConBans, this, "Show banlist");
+	Console()->Register("status", "", CFGFLAG_SERVER, ConStatus, this, "List players");
+	Console()->Register("shutdown", "", CFGFLAG_SERVER, ConShutdown, this, "Shut down");
 
-	Console()->Register("record", "?s", CFGFLAG_SERVER|CFGFLAG_STORE, ConRecord, this, "");
-	Console()->Register("stoprecord", "", CFGFLAG_SERVER, ConStopRecord, this, "");
+	Console()->Register("record", "?s", CFGFLAG_SERVER|CFGFLAG_STORE, ConRecord, this, "Record to a file");
+	Console()->Register("stoprecord", "", CFGFLAG_SERVER, ConStopRecord, this, "Stop recording");
 
-	Console()->Register("reload", "", CFGFLAG_SERVER, ConMapReload, this, "");
+	Console()->Register("reload", "", CFGFLAG_SERVER, ConMapReload, this, "Reload the map");
 
 	Console()->Chain("sv_name", ConchainSpecialInfoupdate, this);
 	Console()->Chain("password", ConchainSpecialInfoupdate, this);
 
 	Console()->Chain("sv_max_clients_per_ip", ConchainMaxclientsperipUpdate, this);
+	Console()->Chain("mod_command", ConchainModCommandUpdate, this);
+	Console()->Chain("console_output_level", ConchainConsoleOutputLevelUpdate, this);
 }
 
 
diff --git a/src/engine/server/server.h b/src/engine/server/server.h
index be36a856..d8fdd8fa 100644
--- a/src/engine/server/server.h
+++ b/src/engine/server/server.h
@@ -49,6 +49,15 @@ public:
 	class IConsole *Console() { return m_pConsole; }
 	class IStorage *Storage() { return m_pStorage; }
 
+	enum
+	{
+		AUTHED_NO=0,
+		AUTHED_MOD,
+		AUTHED_ADMIN,
+
+		MAX_RCONCMD_SEND=16,
+	};
+
 	class CClient
 	{
 	public:
@@ -93,6 +102,8 @@ public:
 		int m_Authed;
 		int m_AuthTries;
 
+		const IConsole::CCommandInfo *m_pRconCmdToSend;
+
 		void Reset();
 	};
 
@@ -102,6 +113,7 @@ public:
 	CSnapshotBuilder m_SnapshotBuilder;
 	CSnapIDPool m_IDPool;
 	CNetServer m_NetServer;
+	CEcon m_Econ;
 
 	IEngineMap *m_pMap;
 
@@ -110,6 +122,8 @@ public:
 	int m_RunServer;
 	int m_MapReload;
 	int m_RconClientID;
+	int m_RconAuthLevel;
+	int m_PrintCBIndex;
 
 	int64 m_Lastheartbeat;
 	//static NETADDR4 master_server;
@@ -134,6 +148,8 @@ public:
 
 	void Kick(int ClientID, const char *pReason);
 
+	void DemoRecorder_HandleAutoStart();
+
 	//int Tick()
 	int64 TickStartTime(int Tick);
 	//int TickSpeed()
@@ -161,6 +177,10 @@ public:
 	void SendRconLine(int ClientID, const char *pLine);
 	static void SendRconLineAuthed(const char *pLine, void *pUser);
 
+	void SendRconCmdAdd(const IConsole::CCommandInfo *pCommandInfo, int ClientID);
+	void SendRconCmdRem(const IConsole::CCommandInfo *pCommandInfo, int ClientID);
+	void UpdateClientRconCommands();
+
 	void ProcessClientPacket(CNetChunk *pPacket);
 
 	void SendServerInfo(NETADDR *pAddr, int Token);
@@ -169,7 +189,6 @@ public:
 	int BanAdd(NETADDR Addr, int Seconds, const char *pReason);
 	int BanRemove(NETADDR Addr);
 
-
 	void PumpNetwork();
 
 	char *GetMapName();
@@ -189,6 +208,8 @@ public:
 	static void ConMapReload(IConsole::IResult *pResult, void *pUser);
 	static void ConchainSpecialInfoupdate(IConsole::IResult *pResult, void *pUserData, IConsole::FCommandCallback pfnCallback, void *pCallbackUserData);
 	static void ConchainMaxclientsperipUpdate(IConsole::IResult *pResult, void *pUserData, IConsole::FCommandCallback pfnCallback, void *pCallbackUserData);
+	static void ConchainModCommandUpdate(IConsole::IResult *pResult, void *pUserData, IConsole::FCommandCallback pfnCallback, void *pCallbackUserData);
+	static void ConchainConsoleOutputLevelUpdate(IConsole::IResult *pResult, void *pUserData, IConsole::FCommandCallback pfnCallback, void *pCallbackUserData);
 
 	void RegisterCommands();
 
diff --git a/src/engine/shared/config_variables.h b/src/engine/shared/config_variables.h
index 31a8128a..c812063a 100644
--- a/src/engine/shared/config_variables.h
+++ b/src/engine/shared/config_variables.h
@@ -82,9 +82,19 @@ MACRO_CONFIG_INT(SvMaxClients, sv_max_clients, 8, 1, MAX_CLIENTS, CFGFLAG_SERVER
 MACRO_CONFIG_INT(SvMaxClientsPerIP, sv_max_clients_per_ip, 4, 1, MAX_CLIENTS, CFGFLAG_SERVER, "Maximum number of clients with the same IP that can connect to the server")
 MACRO_CONFIG_INT(SvHighBandwidth, sv_high_bandwidth, 0, 0, 1, CFGFLAG_SERVER, "Use high bandwidth mode. Doubles the bandwidth required for the server. LAN use only")
 MACRO_CONFIG_INT(SvRegister, sv_register, 1, 0, 1, CFGFLAG_SERVER, "Register server with master server for public listing")
-MACRO_CONFIG_STR(SvRconPassword, sv_rcon_password, 32, "", CFGFLAG_SERVER, "Remote console password")
+MACRO_CONFIG_STR(SvRconPassword, sv_rcon_password, 32, "", CFGFLAG_SERVER, "Remote console password (full access)")
+MACRO_CONFIG_STR(SvRconModPassword, sv_rcon_mod_password, 32, "", CFGFLAG_SERVER, "Remote console password for moderators (limited access)")
 MACRO_CONFIG_INT(SvRconMaxTries, sv_rcon_max_tries, 3, 0, 100, CFGFLAG_SERVER, "Maximum number of tries for remote console authentication")
 MACRO_CONFIG_INT(SvRconBantime, sv_rcon_bantime, 5, 0, 1440, CFGFLAG_SERVER, "The time a client gets banned if remote console authentication fails. 0 makes it just use kick")
+MACRO_CONFIG_INT(SvAutoDemoRecord, sv_auto_demo_record, 0, 0, 1, CFGFLAG_SERVER, "Automatically record demos")
+MACRO_CONFIG_INT(SvAutoDemoMax, sv_auto_demo_max, 10, 0, 1000, CFGFLAG_SERVER, "Maximum number of automatically recorded demos (0 = no limit)")
+
+MACRO_CONFIG_STR(EcBindaddr, ec_bindaddr, 128, "localhost", CFGFLAG_SERVER, "Address to bind the external console to. Anything but 'localhost' is dangerous")
+MACRO_CONFIG_INT(EcPort, ec_port, 0, 0, 0, CFGFLAG_SERVER, "Port to use for the external console")
+MACRO_CONFIG_STR(EcPassword, ec_password, 32, "", CFGFLAG_SERVER, "External console password")
+MACRO_CONFIG_INT(EcBantime, ec_bantime, 0, 0, 1440, CFGFLAG_SERVER, "The time a client gets banned if econ authentication fails. 0 just closes the connection")
+MACRO_CONFIG_INT(EcAuthTimeout, ec_auth_timeout, 30, 1, 120, CFGFLAG_SERVER, "Time in seconds before the the econ authentification times out")
+MACRO_CONFIG_INT(EcOutputLevel, ec_output_level, 1, 0, 2, CFGFLAG_SERVER, "Adjusts the amount of information in the external console")
 
 MACRO_CONFIG_INT(Debug, debug, 0, 0, 1, CFGFLAG_CLIENT|CFGFLAG_SERVER, "Debug mode")
 MACRO_CONFIG_INT(DbgStress, dbg_stress, 0, 0, 0, CFGFLAG_CLIENT|CFGFLAG_SERVER, "Stress systems")
diff --git a/src/engine/shared/console.cpp b/src/engine/shared/console.cpp
index 3fd73543..e4cb1991 100644
--- a/src/engine/shared/console.cpp
+++ b/src/engine/shared/console.cpp
@@ -1,11 +1,15 @@
 /* (c) Magnus Auvinen. See licence.txt in the root of the distribution for more information. */
 /* If you are missing that file, acquire a complete release at teeworlds.com.                */
 #include <new>
+
+#include <base/math.h>
 #include <base/system.h>
-#include <engine/shared/protocol.h>
+
 #include <engine/storage.h>
-#include "console.h"
+#include <engine/shared/protocol.h>
+
 #include "config.h"
+#include "console.h"
 #include "linereader.h"
 
 const char *CConsole::CResult::GetString(unsigned Index)
@@ -29,6 +33,29 @@ float CConsole::CResult::GetFloat(unsigned Index)
 	return str_tofloat(m_apArgs[Index]);
 }
 
+const IConsole::CCommandInfo *CConsole::CCommand::NextCommandInfo(int AccessLevel, int FlagMask) const
+{
+	const CCommand *pInfo = m_pNext;
+	while(pInfo)
+	{
+		if(pInfo->m_Flags&FlagMask && pInfo->m_AccessLevel >= AccessLevel)
+			break;
+		pInfo = pInfo->m_pNext;
+	}
+	return pInfo;
+}
+
+const IConsole::CCommandInfo *CConsole::FirstCommandInfo(int AccessLevel, int FlagMask) const
+{
+	for(const CCommand *pCommand = m_pFirstCommand; pCommand; pCommand = pCommand->m_pNext)
+	{
+		if(pCommand->m_Flags&FlagMask && pCommand->GetAccessLevel() >= AccessLevel)
+			return pCommand;
+	}
+
+	return 0;
+}
+
 // the maximum number of tokens occurs in a string of length CONSOLE_MAX_STR_LENGTH with tokens size 1 separated by single spaces
 
 
@@ -146,20 +173,34 @@ int CConsole::ParseArgs(CResult *pResult, const char *pFormat)
 	return Error;
 }
 
-void CConsole::RegisterPrintCallback(FPrintCallback pfnPrintCallback, void *pUserData)
+int CConsole::RegisterPrintCallback(int OutputLevel, FPrintCallback pfnPrintCallback, void *pUserData)
+{
+	if(m_NumPrintCB == MAX_PRINT_CB)
+		return -1;
+
+	m_aPrintCB[m_NumPrintCB].m_OutputLevel = clamp(OutputLevel, (int)(OUTPUT_LEVEL_STANDARD), (int)(OUTPUT_LEVEL_DEBUG));
+	m_aPrintCB[m_NumPrintCB].m_pfnPrintCallback = pfnPrintCallback;
+	m_aPrintCB[m_NumPrintCB].m_pPrintCallbackUserdata = pUserData;
+	return m_NumPrintCB++;
+}
+
+void CConsole::SetPrintOutputLevel(int Index, int OutputLevel)
 {
-	m_pfnPrintCallback = pfnPrintCallback;
-	m_pPrintCallbackUserdata = pUserData;
+	if(Index >= 0 && Index < MAX_PRINT_CB)
+		m_aPrintCB[Index].m_OutputLevel = clamp(OutputLevel, (int)(OUTPUT_LEVEL_STANDARD), (int)(OUTPUT_LEVEL_DEBUG));
 }
 
 void CConsole::Print(int Level, const char *pFrom, const char *pStr)
 {
 	dbg_msg(pFrom ,"%s", pStr);
-	if(Level <= g_Config.m_ConsoleOutputLevel && m_pfnPrintCallback)
+	for(int i = 0; i < m_NumPrintCB; ++i)
 	{
-		char aBuf[1024];
-		str_format(aBuf, sizeof(aBuf), "[%s]: %s", pFrom, pStr);
-		m_pfnPrintCallback(aBuf, m_pPrintCallbackUserdata);
+		if(Level <= m_aPrintCB[i].m_OutputLevel && m_aPrintCB[i].m_pfnPrintCallback)
+		{
+			char aBuf[1024];
+			str_format(aBuf, sizeof(aBuf), "[%s]: %s", pFrom, pStr);
+			m_aPrintCB[i].m_pfnPrintCallback(aBuf, m_aPrintCB[i].m_pPrintCallbackUserdata);
+		}
 	}
 }
 
@@ -247,38 +288,47 @@ void CConsole::ExecuteLineStroked(int Stroke, const char *pStr)
 		if(ParseStart(&Result, pStr, (pEnd-pStr) + 1) != 0)
 			return;
 
-		if (!*Result.m_pCommand)
+		if(!*Result.m_pCommand)
 			return;
 
 		CCommand *pCommand = FindCommand(Result.m_pCommand, m_FlagMask);
 
 		if(pCommand)
 		{
-			int IsStrokeCommand = 0;
-			if(Result.m_pCommand[0] == '+')
-			{
-				// insert the stroke direction token
-				Result.AddArgument(m_paStrokeStr[Stroke]);
-				IsStrokeCommand = 1;
-			}
-
-			if(Stroke || IsStrokeCommand)
+			if(pCommand->GetAccessLevel() >= m_AccessLevel)
 			{
-				if(ParseArgs(&Result, pCommand->m_pParams))
+				int IsStrokeCommand = 0;
+				if(Result.m_pCommand[0] == '+')
 				{
-					char aBuf[256];
-					str_format(aBuf, sizeof(aBuf), "Invalid arguments... Usage: %s %s", pCommand->m_pName, pCommand->m_pParams);
-					Print(OUTPUT_LEVEL_STANDARD, "Console", aBuf);
+					// insert the stroke direction token
+					Result.AddArgument(m_paStrokeStr[Stroke]);
+					IsStrokeCommand = 1;
 				}
-				else if(m_StoreCommands && pCommand->m_Flags&CFGFLAG_STORE)
+
+				if(Stroke || IsStrokeCommand)
 				{
-					m_ExecutionQueue.AddEntry();
-					m_ExecutionQueue.m_pLast->m_pfnCommandCallback = pCommand->m_pfnCallback;
-					m_ExecutionQueue.m_pLast->m_pCommandUserData = pCommand->m_pUserData;
-					m_ExecutionQueue.m_pLast->m_Result = Result;
+					if(ParseArgs(&Result, pCommand->m_pParams))
+					{
+						char aBuf[256];
+						str_format(aBuf, sizeof(aBuf), "Invalid arguments... Usage: %s %s", pCommand->m_pName, pCommand->m_pParams);
+						Print(OUTPUT_LEVEL_STANDARD, "Console", aBuf);
+					}
+					else if(m_StoreCommands && pCommand->m_Flags&CFGFLAG_STORE)
+					{
+						m_ExecutionQueue.AddEntry();
+						m_ExecutionQueue.m_pLast->m_pfnCommandCallback = pCommand->m_pfnCallback;
+						m_ExecutionQueue.m_pLast->m_pCommandUserData = pCommand->m_pUserData;
+						m_ExecutionQueue.m_pLast->m_Result = Result;
+					}
+					else
+						pCommand->m_pfnCallback(&Result, pCommand->m_pUserData);
 				}
-				else
-					pCommand->m_pfnCallback(&Result, pCommand->m_pUserData);
+			}
+			else if(Stroke)
+			{
+				char aBuf[256];
+				str_format(aBuf, sizeof(aBuf), "Access for command %s denied.", Result.m_pCommand);
+				Print(OUTPUT_LEVEL_STANDARD, "Console", aBuf);
 			}
 		}
 		else if(Stroke)
@@ -292,12 +342,11 @@ void CConsole::ExecuteLineStroked(int Stroke, const char *pStr)
 	}
 }
 
-void CConsole::PossibleCommands(const char *pStr, int FlagMask, FPossibleCallback pfnCallback, void *pUser)
+void CConsole::PossibleCommands(const char *pStr, int FlagMask, bool Temp, FPossibleCallback pfnCallback, void *pUser)
 {
-	CCommand *pCommand;
-	for(pCommand = m_pFirstCommand; pCommand; pCommand = pCommand->m_pNext)
+	for(CCommand *pCommand = m_pFirstCommand; pCommand; pCommand = pCommand->m_pNext)
 	{
-		if(pCommand->m_Flags&FlagMask)
+		if(pCommand->m_Flags&FlagMask && pCommand->m_Temp == Temp)
 		{
 			if(str_find_nocase(pCommand->m_pName, pStr))
 				pfnCallback(pCommand->m_pName, pUser);
@@ -307,8 +356,7 @@ void CConsole::PossibleCommands(const char *pStr, int FlagMask, FPossibleCallbac
 
 CConsole::CCommand *CConsole::FindCommand(const char *pName, int FlagMask)
 {
-	CCommand *pCommand;
-	for (pCommand = m_pFirstCommand; pCommand; pCommand = pCommand->m_pNext)
+	for(CCommand *pCommand = m_pFirstCommand; pCommand; pCommand = pCommand->m_pNext)
 	{
 		if(pCommand->m_Flags&FlagMask)
 		{
@@ -383,6 +431,62 @@ void CConsole::Con_Exec(IResult *pResult, void *pUserData)
 	((CConsole*)pUserData)->ExecuteFile(pResult->GetString(0));
 }
 
+void CConsole::ConModCommandAccess(IResult *pResult, void *pUser)
+{
+	CConsole* pConsole = static_cast<CConsole *>(pUser);
+	char aBuf[128];
+	CCommand *pCommand = pConsole->FindCommand(pResult->GetString(0), CFGFLAG_SERVER);
+	if(pCommand)
+	{
+		if(pResult->NumArguments() == 2)
+		{
+			pCommand->SetAccessLevel(pResult->GetInteger(1));
+			str_format(aBuf, sizeof(aBuf), "moderator access for '%s' is now %s", pResult->GetString(0), pCommand->GetAccessLevel() ? "enabled" : "disabled");
+		}
+		else
+			str_format(aBuf, sizeof(aBuf), "moderator access for '%s' is %s", pResult->GetString(0), pCommand->GetAccessLevel() ? "enabled" : "disabled");
+	}
+	else
+		str_format(aBuf, sizeof(aBuf), "No such command: '%s'.", pResult->GetString(0));
+
+	pConsole->Print(OUTPUT_LEVEL_STANDARD, "Console", aBuf);
+}
+
+void CConsole::ConModCommandStatus(IResult *pResult, void *pUser)
+{
+	CConsole* pConsole = static_cast<CConsole *>(pUser);
+	char aBuf[240];
+	mem_zero(aBuf, sizeof(aBuf));
+	int Used = 0;
+
+	for(CCommand *pCommand = pConsole->m_pFirstCommand; pCommand; pCommand = pCommand->m_pNext)
+	{
+		if(pCommand->m_Flags&pConsole->m_FlagMask && pCommand->GetAccessLevel() == ACCESS_LEVEL_MOD)
+		{
+			int Length = str_length(pCommand->m_pName);
+			if(Used + Length + 2 < (int)(sizeof(aBuf)))
+			{
+				if(Used > 0)
+				{
+					Used += 2;
+					str_append(aBuf, ", ", sizeof(aBuf));
+				}
+				str_append(aBuf, pCommand->m_pName, sizeof(aBuf));
+				Used += Length;
+			}
+			else
+			{
+				pConsole->Print(OUTPUT_LEVEL_STANDARD, "Console", aBuf);
+				mem_zero(aBuf, sizeof(aBuf));
+				str_copy(aBuf, pCommand->m_pName, sizeof(aBuf));
+				Used = Length;
+			}
+		}
+	}
+	if(Used > 0)
+		pConsole->Print(OUTPUT_LEVEL_STANDARD, "Console", aBuf);
+}
+
 struct CIntVariableData
 {
 	IConsole *m_pConsole;
@@ -463,14 +567,17 @@ static void StrVariableCommand(IConsole::IResult *pResult, void *pUserData)
 CConsole::CConsole(int FlagMask)
 {
 	m_FlagMask = FlagMask;
+	m_AccessLevel = ACCESS_LEVEL_ADMIN;
+	m_pRecycleList = 0;
+	m_TempCommands.Reset();
 	m_StoreCommands = true;
 	m_paStrokeStr[0] = "0";
 	m_paStrokeStr[1] = "1";
 	m_ExecutionQueue.Reset();
 	m_pFirstCommand = 0;
 	m_pFirstExec = 0;
-	m_pPrintCallbackUserdata = 0;
-	m_pfnPrintCallback = 0;
+	mem_zero(m_aPrintCB, sizeof(m_aPrintCB));
+	m_NumPrintCB = 0;
 
 	m_pStorage = 0;
 
@@ -478,6 +585,9 @@ CConsole::CConsole(int FlagMask)
 	Register("echo", "r", CFGFLAG_SERVER|CFGFLAG_CLIENT, Con_Echo, this, "Echo the text");
 	Register("exec", "r", CFGFLAG_SERVER|CFGFLAG_CLIENT, Con_Exec, this, "Execute the specified file");
 
+	Register("mod_command", "s?i", CFGFLAG_SERVER, ConModCommandAccess, this, "Specify command accessibility for moderators");
+	Register("mod_status", "", CFGFLAG_SERVER, ConModCommandStatus, this, "List all commands which are accessible for moderators");
+
 	// TODO: this should disappear
 	#define MACRO_CONFIG_INT(Name,ScriptName,Def,Min,Max,Flags,Desc) \
 	{ \
@@ -521,20 +631,131 @@ void CConsole::ParseArguments(int NumArgs, const char **ppArguments)
 	}
 }
 
+void CConsole::AddCommandSorted(CCommand *pCommand)
+{
+	if(!m_pFirstCommand || str_comp(pCommand->m_pName, m_pFirstCommand->m_pName) < 0)
+	{
+		if(m_pFirstCommand && m_pFirstCommand->m_pNext)
+			pCommand->m_pNext = m_pFirstCommand;
+		else
+			pCommand->m_pNext = 0;
+		m_pFirstCommand = pCommand;
+	}
+	else
+	{
+		for(CCommand *p = m_pFirstCommand; p; p = p->m_pNext)
+		{
+			if(!p->m_pNext || str_comp(pCommand->m_pName, p->m_pNext->m_pName) < 0)
+			{
+				pCommand->m_pNext = p->m_pNext;
+				p->m_pNext = pCommand;
+				break;
+			}
+		}
+	}
+}
+
 void CConsole::Register(const char *pName, const char *pParams,
 	int Flags, FCommandCallback pfnFunc, void *pUser, const char *pHelp)
 {
-	CCommand *pCommand = (CCommand *)mem_alloc(sizeof(CCommand), sizeof(void*));
+	CCommand *pCommand = new(mem_alloc(sizeof(CCommand), sizeof(void*))) CCommand;
 	pCommand->m_pfnCallback = pfnFunc;
 	pCommand->m_pUserData = pUser;
-	pCommand->m_pHelp = pHelp;
+
 	pCommand->m_pName = pName;
+	pCommand->m_pHelp = pHelp;
 	pCommand->m_pParams = pParams;
+	
+	pCommand->m_Flags = Flags;
+	pCommand->m_Temp = false;
+
+	AddCommandSorted(pCommand);
+}
+
+void CConsole::RegisterTemp(const char *pName, const char *pParams,	int Flags, const char *pHelp)
+{
+	CCommand *pCommand;
+	if(m_pRecycleList)
+	{
+		pCommand = m_pRecycleList;
+		str_copy(const_cast<char *>(pCommand->m_pName), pName, TEMPCMD_NAME_LENGTH);
+		str_copy(const_cast<char *>(pCommand->m_pHelp), pHelp, TEMPCMD_HELP_LENGTH);
+		str_copy(const_cast<char *>(pCommand->m_pParams), pParams, TEMPCMD_PARAMS_LENGTH);
+
+		m_pRecycleList = m_pRecycleList->m_pNext;
+	}
+	else
+	{
+		pCommand = new(m_TempCommands.Allocate(sizeof(CCommand))) CCommand;
+		char *pMem = static_cast<char *>(m_TempCommands.Allocate(TEMPCMD_NAME_LENGTH));
+		str_copy(pMem, pName, TEMPCMD_NAME_LENGTH);
+		pCommand->m_pName = pMem;
+		pMem = static_cast<char *>(m_TempCommands.Allocate(TEMPCMD_HELP_LENGTH));
+		str_copy(pMem, pHelp, TEMPCMD_HELP_LENGTH);
+		pCommand->m_pHelp = pMem;
+		pMem = static_cast<char *>(m_TempCommands.Allocate(TEMPCMD_PARAMS_LENGTH));
+		str_copy(pMem, pParams, TEMPCMD_PARAMS_LENGTH);
+		pCommand->m_pParams = pMem;
+	}
+
+	pCommand->m_pfnCallback = 0;
+	pCommand->m_pUserData = 0;	
 	pCommand->m_Flags = Flags;
+	pCommand->m_Temp = true;
+
+	AddCommandSorted(pCommand);
+}
+
+void CConsole::DeregisterTemp(const char *pName)
+{
+	if(!m_pFirstCommand)
+		return;
+
+	CCommand *pRemoved = 0;
+
+	// remove temp entry from command list
+	if(m_pFirstCommand->m_Temp && str_comp(m_pFirstCommand->m_pName, pName) == 0)
+	{
+		pRemoved = m_pFirstCommand;
+		m_pFirstCommand = m_pFirstCommand->m_pNext;
+	}
+	else
+	{
+		for(CCommand *pCommand = m_pFirstCommand; pCommand->m_pNext; pCommand = pCommand->m_pNext)
+			if(pCommand->m_pNext->m_Temp && str_comp(pCommand->m_pNext->m_pName, pName) == 0)
+			{
+				pRemoved = pCommand->m_pNext;
+				pCommand->m_pNext = pCommand->m_pNext->m_pNext;
+				break;
+			}
+	}
+	
+	// add to recycle list
+	if(pRemoved)
+	{
+		pRemoved->m_pNext = m_pRecycleList;
+		m_pRecycleList = pRemoved;
+	}
+}
 
+void CConsole::DeregisterTempAll()
+{
+	// set non temp as first one
+	for(; m_pFirstCommand && m_pFirstCommand->m_Temp; m_pFirstCommand = m_pFirstCommand->m_pNext);
+	
+	// remove temp entries from command list
+	for(CCommand *pCommand = m_pFirstCommand; pCommand && pCommand->m_pNext; pCommand = pCommand->m_pNext)
+	{
+		CCommand *pNext = pCommand->m_pNext;
+		if(pNext->m_Temp)
+		{
+			for(; pNext && pNext->m_Temp; pNext = pNext->m_pNext);
+			pCommand->m_pNext = pNext;
+		}
+	}
 
-	pCommand->m_pNext = m_pFirstCommand;
-	m_pFirstCommand = pCommand;
+	m_TempCommands.Reset();
+	m_pRecycleList = 0;
 }
 
 void CConsole::Con_Chain(IResult *pResult, void *pUserData)
@@ -580,9 +801,18 @@ void CConsole::StoreCommands(bool Store)
 }
 
 
-IConsole::CCommandInfo *CConsole::GetCommandInfo(const char *pName, int FlagMask)
+const IConsole::CCommandInfo *CConsole::GetCommandInfo(const char *pName, int FlagMask, bool Temp)
 {
-	return FindCommand(pName, FlagMask);
+	for(CCommand *pCommand = m_pFirstCommand; pCommand; pCommand = pCommand->m_pNext)
+	{
+		if(pCommand->m_Flags&FlagMask && pCommand->m_Temp == Temp)
+		{
+			if(str_comp_nocase(pCommand->m_pName, pName) == 0)
+				return pCommand;
+		}
+	}
+
+	return 0;
 }
 
 
diff --git a/src/engine/shared/console.h b/src/engine/shared/console.h
index 0866d8e3..6989c696 100644
--- a/src/engine/shared/console.h
+++ b/src/engine/shared/console.h
@@ -13,8 +13,13 @@ class CConsole : public IConsole
 	public:
 		CCommand *m_pNext;
 		int m_Flags;
+		bool m_Temp;
 		FCommandCallback m_pfnCallback;
 		void *m_pUserData;
+
+		virtual const CCommandInfo *NextCommandInfo(int AccessLevel, int FlagMask) const;
+
+		void SetAccessLevel(int AccessLevel) { m_AccessLevel = clamp(AccessLevel, (int)(ACCESS_LEVEL_ADMIN), (int)(ACCESS_LEVEL_MOD)); }
 	};
 
 
@@ -41,16 +46,27 @@ class CConsole : public IConsole
 
 	CExecFile *m_pFirstExec;
 	class IStorage *m_pStorage;
+	int m_AccessLevel;
+
+	CCommand *m_pRecycleList;
+	CHeap m_TempCommands;
 
 	static void Con_Chain(IResult *pResult, void *pUserData);
 	static void Con_Echo(IResult *pResult, void *pUserData);
 	static void Con_Exec(IResult *pResult, void *pUserData);
+	static void ConModCommandAccess(IResult *pResult, void *pUser);
+	static void ConModCommandStatus(IConsole::IResult *pResult, void *pUser);
 
 	void ExecuteFileRecurse(const char *pFilename);
 	void ExecuteLineStroked(int Stroke, const char *pStr);
 
-	FPrintCallback m_pfnPrintCallback;
-	void *m_pPrintCallbackUserdata;
+	struct
+	{
+		int m_OutputLevel;
+		FPrintCallback m_pfnPrintCallback;
+		void *m_pPrintCallbackUserdata;
+	} m_aPrintCB[MAX_PRINT_CB];
+	int m_NumPrintCB;
 
 	enum
 	{
@@ -134,16 +150,21 @@ class CConsole : public IConsole
 		}
 	} m_ExecutionQueue;
 
+	void AddCommandSorted(CCommand *pCommand);
 	CCommand *FindCommand(const char *pName, int FlagMask);
 
 public:
 	CConsole(int FlagMask);
 
-	virtual CCommandInfo *GetCommandInfo(const char *pName, int FlagMask);
-	virtual void PossibleCommands(const char *pStr, int FlagMask, FPossibleCallback pfnCallback, void *pUser) ;
+	virtual const CCommandInfo *FirstCommandInfo(int AccessLevel, int Flagmask) const;
+	virtual const CCommandInfo *GetCommandInfo(const char *pName, int FlagMask, bool Temp);
+	virtual void PossibleCommands(const char *pStr, int FlagMask, bool Temp, FPossibleCallback pfnCallback, void *pUser);
 
 	virtual void ParseArguments(int NumArgs, const char **ppArguments);
 	virtual void Register(const char *pName, const char *pParams, int Flags, FCommandCallback pfnFunc, void *pUser, const char *pHelp);
+	virtual void RegisterTemp(const char *pName, const char *pParams, int Flags, const char *pHelp);
+	virtual void DeregisterTemp(const char *pName);
+	virtual void DeregisterTempAll();
 	virtual void Chain(const char *pName, FChainCommandCallback pfnChainFunc, void *pUser);
 	virtual void StoreCommands(bool Store);
 
@@ -151,8 +172,11 @@ public:
 	virtual void ExecuteLine(const char *pStr);
 	virtual void ExecuteFile(const char *pFilename);
 
-	virtual void RegisterPrintCallback(FPrintCallback pfnPrintCallback, void *pUserData);
+	virtual int RegisterPrintCallback(int OutputLevel, FPrintCallback pfnPrintCallback, void *pUserData);
+	virtual void SetPrintOutputLevel(int Index, int OutputLevel);
 	virtual void Print(int Level, const char *pFrom, const char *pStr);
+
+	void SetAccessLevel(int AccessLevel) { m_AccessLevel = clamp(AccessLevel, (int)(ACCESS_LEVEL_ADMIN), (int)(ACCESS_LEVEL_MOD)); }
 };
 
 #endif
diff --git a/src/engine/shared/datafile.cpp b/src/engine/shared/datafile.cpp
index 00410038..e2215635 100644
--- a/src/engine/shared/datafile.cpp
+++ b/src/engine/shared/datafile.cpp
@@ -422,6 +422,25 @@ unsigned CDataFileReader::Crc()
 	return m_pDataFile->m_Crc;
 }
 
+
+CDataFileWriter::CDataFileWriter()
+{
+	m_File = 0;
+	m_pItemTypes = static_cast<CItemTypeInfo *>(mem_alloc(sizeof(CItemTypeInfo) * MAX_ITEM_TYPES, 1));
+	m_pItems = static_cast<CItemInfo *>(mem_alloc(sizeof(CItemInfo) * MAX_ITEMS, 1));
+	m_pDatas = static_cast<CDataInfo *>(mem_alloc(sizeof(CDataInfo) * MAX_DATAS, 1));
+}
+
+CDataFileWriter::~CDataFileWriter()
+{
+	mem_free(m_pItemTypes);
+	m_pItemTypes = 0;
+	mem_free(m_pItems);
+	m_pItems = 0;
+	mem_free(m_pDatas);
+	m_pDatas = 0;
+}
+
 bool CDataFileWriter::Open(class IStorage *pStorage, const char *pFilename)
 {
 	dbg_assert(!m_File, "a file already exists");
@@ -432,12 +451,12 @@ bool CDataFileWriter::Open(class IStorage *pStorage, const char *pFilename)
 	m_NumItems = 0;
 	m_NumDatas = 0;
 	m_NumItemTypes = 0;
-	mem_zero(&m_aItemTypes, sizeof(m_aItemTypes));
+	mem_zero(m_pItemTypes, sizeof(CItemTypeInfo) * MAX_ITEM_TYPES);
 
-	for(int i = 0; i < 0xffff; i++)
+	for(int i = 0; i < MAX_ITEM_TYPES; i++)
 	{
-		m_aItemTypes[i].m_First = -1;
-		m_aItemTypes[i].m_Last = -1;
+		m_pItemTypes[i].m_First = -1;
+		m_pItemTypes[i].m_Last = -1;
 	}
 
 	return true;
@@ -451,29 +470,29 @@ int CDataFileWriter::AddItem(int Type, int ID, int Size, void *pData)
 	dbg_assert(m_NumItems < 1024, "too many items");
 	dbg_assert(Size%sizeof(int) == 0, "incorrect boundary");
 
-	m_aItems[m_NumItems].m_Type = Type;
-	m_aItems[m_NumItems].m_ID = ID;
-	m_aItems[m_NumItems].m_Size = Size;
+	m_pItems[m_NumItems].m_Type = Type;
+	m_pItems[m_NumItems].m_ID = ID;
+	m_pItems[m_NumItems].m_Size = Size;
 
 	// copy data
-	m_aItems[m_NumItems].m_pData = mem_alloc(Size, 1);
-	mem_copy(m_aItems[m_NumItems].m_pData, pData, Size);
+	m_pItems[m_NumItems].m_pData = mem_alloc(Size, 1);
+	mem_copy(m_pItems[m_NumItems].m_pData, pData, Size);
 
-	if(!m_aItemTypes[Type].m_Num) // count item types
+	if(!m_pItemTypes[Type].m_Num) // count item types
 		m_NumItemTypes++;
 
 	// link
-	m_aItems[m_NumItems].m_Prev = m_aItemTypes[Type].m_Last;
-	m_aItems[m_NumItems].m_Next = -1;
+	m_pItems[m_NumItems].m_Prev = m_pItemTypes[Type].m_Last;
+	m_pItems[m_NumItems].m_Next = -1;
 
-	if(m_aItemTypes[Type].m_Last != -1)
-		m_aItems[m_aItemTypes[Type].m_Last].m_Next = m_NumItems;
-	m_aItemTypes[Type].m_Last = m_NumItems;
+	if(m_pItemTypes[Type].m_Last != -1)
+		m_pItems[m_pItemTypes[Type].m_Last].m_Next = m_NumItems;
+	m_pItemTypes[Type].m_Last = m_NumItems;
 
-	if(m_aItemTypes[Type].m_First == -1)
-		m_aItemTypes[Type].m_First = m_NumItems;
+	if(m_pItemTypes[Type].m_First == -1)
+		m_pItemTypes[Type].m_First = m_NumItems;
 
-	m_aItemTypes[Type].m_Num++;
+	m_pItemTypes[Type].m_Num++;
 
 	m_NumItems++;
 	return m_NumItems-1;
@@ -485,7 +504,7 @@ int CDataFileWriter::AddData(int Size, void *pData)
 
 	dbg_assert(m_NumDatas < 1024, "too much data");
 
-	CDataInfo *pInfo = &m_aDatas[m_NumDatas];
+	CDataInfo *pInfo = &m_pDatas[m_NumDatas];
 	unsigned long s = compressBound(Size);
 	void *pCompData = mem_alloc(s, 1); // temporary buffer that we use during compression
 
@@ -540,13 +559,13 @@ int CDataFileWriter::Finish()
 	for(int i = 0; i < m_NumItems; i++)
 	{
 		if(DEBUG)
-			dbg_msg("datafile", "item=%d size=%d (%d)", i, m_aItems[i].m_Size, m_aItems[i].m_Size+sizeof(CDatafileItem));
-		ItemSize += m_aItems[i].m_Size + sizeof(CDatafileItem);
+			dbg_msg("datafile", "item=%d size=%d (%d)", i, m_pItems[i].m_Size, m_pItems[i].m_Size+sizeof(CDatafileItem));
+		ItemSize += m_pItems[i].m_Size + sizeof(CDatafileItem);
 	}
 
 
 	for(int i = 0; i < m_NumDatas; i++)
-		DataSize += m_aDatas[i].m_CompressedSize;
+		DataSize += m_pDatas[i].m_CompressedSize;
 
 	// calculate the complete size
 	TypesSize = m_NumItemTypes*sizeof(CDatafileItemType);
@@ -587,30 +606,30 @@ int CDataFileWriter::Finish()
 	// write types
 	for(int i = 0, Count = 0; i < 0xffff; i++)
 	{
-		if(m_aItemTypes[i].m_Num)
+		if(m_pItemTypes[i].m_Num)
 		{
 			// write info
 			CDatafileItemType Info;
 			Info.m_Type = i;
 			Info.m_Start = Count;
-			Info.m_Num = m_aItemTypes[i].m_Num;
+			Info.m_Num = m_pItemTypes[i].m_Num;
 			if(DEBUG)
 				dbg_msg("datafile", "writing type=%x start=%d num=%d", Info.m_Type, Info.m_Start, Info.m_Num);
 #if defined(CONF_ARCH_ENDIAN_BIG)
 			swap_endian(&Info, sizeof(int), sizeof(CDatafileItemType)/sizeof(int));
 #endif
 			io_write(m_File, &Info, sizeof(Info));
-			Count += m_aItemTypes[i].m_Num;
+			Count += m_pItemTypes[i].m_Num;
 		}
 	}
 
 	// write item offsets
 	for(int i = 0, Offset = 0; i < 0xffff; i++)
 	{
-		if(m_aItemTypes[i].m_Num)
+		if(m_pItemTypes[i].m_Num)
 		{
-			// write all m_aItems in of this type
-			int k = m_aItemTypes[i].m_First;
+			// write all m_pItems in of this type
+			int k = m_pItemTypes[i].m_First;
 			while(k != -1)
 			{
 				if(DEBUG)
@@ -620,10 +639,10 @@ int CDataFileWriter::Finish()
 				swap_endian(&Temp, sizeof(int), sizeof(Temp)/sizeof(int));
 #endif
 				io_write(m_File, &Temp, sizeof(Temp));
-				Offset += m_aItems[k].m_Size + sizeof(CDatafileItem);
+				Offset += m_pItems[k].m_Size + sizeof(CDatafileItem);
 
 				// next
-				k = m_aItems[k].m_Next;
+				k = m_pItems[k].m_Next;
 			}
 		}
 	}
@@ -638,45 +657,45 @@ int CDataFileWriter::Finish()
 		swap_endian(&Temp, sizeof(int), sizeof(Temp)/sizeof(int));
 #endif
 		io_write(m_File, &Temp, sizeof(Temp));
-		Offset += m_aDatas[i].m_CompressedSize;
+		Offset += m_pDatas[i].m_CompressedSize;
 	}
 
 	// write data uncompressed sizes
 	for(int i = 0; i < m_NumDatas; i++)
 	{
 		if(DEBUG)
-			dbg_msg("datafile", "writing data uncompressed size num=%d size=%d", i, m_aDatas[i].m_UncompressedSize);
-		int UncompressedSize = m_aDatas[i].m_UncompressedSize;
+			dbg_msg("datafile", "writing data uncompressed size num=%d size=%d", i, m_pDatas[i].m_UncompressedSize);
+		int UncompressedSize = m_pDatas[i].m_UncompressedSize;
 #if defined(CONF_ARCH_ENDIAN_BIG)
 		swap_endian(&UncompressedSize, sizeof(int), sizeof(UncompressedSize)/sizeof(int));
 #endif
 		io_write(m_File, &UncompressedSize, sizeof(UncompressedSize));
 	}
 
-	// write m_aItems
+	// write m_pItems
 	for(int i = 0; i < 0xffff; i++)
 	{
-		if(m_aItemTypes[i].m_Num)
+		if(m_pItemTypes[i].m_Num)
 		{
-			// write all m_aItems in of this type
-			int k = m_aItemTypes[i].m_First;
+			// write all m_pItems in of this type
+			int k = m_pItemTypes[i].m_First;
 			while(k != -1)
 			{
 				CDatafileItem Item;
-				Item.m_TypeAndID = (i<<16)|m_aItems[k].m_ID;
-				Item.m_Size = m_aItems[k].m_Size;
+				Item.m_TypeAndID = (i<<16)|m_pItems[k].m_ID;
+				Item.m_Size = m_pItems[k].m_Size;
 				if(DEBUG)
-					dbg_msg("datafile", "writing item type=%x idx=%d id=%d size=%d", i, k, m_aItems[k].m_ID, m_aItems[k].m_Size);
+					dbg_msg("datafile", "writing item type=%x idx=%d id=%d size=%d", i, k, m_pItems[k].m_ID, m_pItems[k].m_Size);
 
 #if defined(CONF_ARCH_ENDIAN_BIG)
 				swap_endian(&Item, sizeof(int), sizeof(Item)/sizeof(int));
-				swap_endian(m_aItems[k].m_pData, sizeof(int), m_aItems[k].m_Size/sizeof(int));
+				swap_endian(m_pItems[k].m_pData, sizeof(int), m_pItems[k].m_Size/sizeof(int));
 #endif
 				io_write(m_File, &Item, sizeof(Item));
-				io_write(m_File, m_aItems[k].m_pData, m_aItems[k].m_Size);
+				io_write(m_File, m_pItems[k].m_pData, m_pItems[k].m_Size);
 
 				// next
-				k = m_aItems[k].m_Next;
+				k = m_pItems[k].m_Next;
 			}
 		}
 	}
@@ -685,15 +704,15 @@ int CDataFileWriter::Finish()
 	for(int i = 0; i < m_NumDatas; i++)
 	{
 		if(DEBUG)
-			dbg_msg("datafile", "writing data id=%d size=%d", i, m_aDatas[i].m_CompressedSize);
-		io_write(m_File, m_aDatas[i].m_pCompressedData, m_aDatas[i].m_CompressedSize);
+			dbg_msg("datafile", "writing data id=%d size=%d", i, m_pDatas[i].m_CompressedSize);
+		io_write(m_File, m_pDatas[i].m_pCompressedData, m_pDatas[i].m_CompressedSize);
 	}
 
 	// free data
 	for(int i = 0; i < m_NumItems; i++)
-		mem_free(m_aItems[i].m_pData);
+		mem_free(m_pItems[i].m_pData);
 	for(int i = 0; i < m_NumDatas; ++i)
-		mem_free(m_aDatas[i].m_pCompressedData);
+		mem_free(m_pDatas[i].m_pCompressedData);
 
 	io_close(m_File);
 	m_File = 0;
diff --git a/src/engine/shared/datafile.h b/src/engine/shared/datafile.h
index 9f27f968..cafce20e 100644
--- a/src/engine/shared/datafile.h
+++ b/src/engine/shared/datafile.h
@@ -61,16 +61,24 @@ class CDataFileWriter
 		int m_Last;
 	};
 
+	enum
+	{
+		MAX_ITEM_TYPES=0xffff,
+		MAX_ITEMS=1024,
+		MAX_DATAS=1024,
+	};
+
 	IOHANDLE m_File;
 	int m_NumItems;
 	int m_NumDatas;
 	int m_NumItemTypes;
-	CItemTypeInfo m_aItemTypes[0xffff];
-	CItemInfo m_aItems[1024];
-	CDataInfo m_aDatas[1024];
+	CItemTypeInfo *m_pItemTypes;
+	CItemInfo *m_pItems;
+	CDataInfo *m_pDatas;
 
 public:
-	CDataFileWriter() : m_File(0) {}
+	CDataFileWriter();
+	~CDataFileWriter();
 	bool Open(class IStorage *pStorage, const char *Filename);
 	int AddData(int Size, void *pData);
 	int AddDataSwapped(int Size, void *pData);
diff --git a/src/engine/shared/econ.cpp b/src/engine/shared/econ.cpp
new file mode 100644
index 00000000..617cdbd6
--- /dev/null
+++ b/src/engine/shared/econ.cpp
@@ -0,0 +1,173 @@
+#include <engine/console.h>
+#include <engine/shared/config.h>
+
+#include "econ.h"
+
+int CEcon::NewClientCallback(int ClientID, void *pUser)
+{
+	CEcon *pThis = (CEcon *)pUser;
+
+	NETADDR Addr = pThis->m_NetConsole.ClientAddr(ClientID);
+	char aAddrStr[NETADDR_MAXSTRSIZE];
+	net_addr_str(&Addr, aAddrStr, sizeof(aAddrStr));
+	char aBuf[128];
+	str_format(aBuf, sizeof(aBuf), "client accepted. cid=%d addr=%s'", ClientID, aAddrStr);
+	pThis->Console()->Print(IConsole::OUTPUT_LEVEL_ADDINFO, "econ", aBuf);
+
+	pThis->m_aClients[ClientID].m_State = CClient::STATE_CONNECTED;
+	pThis->m_aClients[ClientID].m_TimeConnected = time_get();
+	pThis->m_aClients[ClientID].m_AuthTries = 0;
+
+	pThis->m_NetConsole.Send(ClientID, "Enter password:");
+	return 0;
+}
+
+int CEcon::DelClientCallback(int ClientID, const char *pReason, void *pUser)
+{
+	CEcon *pThis = (CEcon *)pUser;
+
+	NETADDR Addr = pThis->m_NetConsole.ClientAddr(ClientID);
+	char aAddrStr[NETADDR_MAXSTRSIZE];
+	net_addr_str(&Addr, aAddrStr, sizeof(aAddrStr));
+	char aBuf[256];
+	str_format(aBuf, sizeof(aBuf), "client dropped. cid=%d addr=%s reason='%s'", ClientID, aAddrStr, pReason);
+	pThis->Console()->Print(IConsole::OUTPUT_LEVEL_ADDINFO, "econ", aBuf);
+
+	pThis->m_aClients[ClientID].m_State = CClient::STATE_EMPTY;
+	return 0;
+}
+
+void CEcon::SendLineCB(const char *pLine, void *pUserData)
+{
+	static_cast<CEcon *>(pUserData)->Send(-1, pLine);
+}
+
+void CEcon::ConchainEconOutputLevelUpdate(IConsole::IResult *pResult, void *pUserData, IConsole::FCommandCallback pfnCallback, void *pCallbackUserData)
+{
+	pfnCallback(pResult, pCallbackUserData);
+	if(pResult->NumArguments() == 1)
+	{
+		CEcon *pThis = static_cast<CEcon *>(pUserData);
+		pThis->Console()->SetPrintOutputLevel(pThis->m_PrintCBIndex, pResult->GetInteger(0));
+	}
+}
+
+void CEcon::Init(IConsole *pConsole)
+{
+	m_pConsole = pConsole;
+
+	for(int i = 0; i < NET_MAX_CONSOLE_CLIENTS; i++)
+		m_aClients[i].m_State = CClient::STATE_EMPTY;
+
+	m_Ready = false;
+
+	if(g_Config.m_EcPort == 0 || g_Config.m_EcPassword[0] == 0)
+		return;
+
+	NETADDR BindAddr;
+	if(g_Config.m_EcBindaddr[0] && net_host_lookup(g_Config.m_EcBindaddr, &BindAddr, NETTYPE_ALL) == 0)
+		BindAddr.port = g_Config.m_EcPort;
+	else
+	{
+		mem_zero(&BindAddr, sizeof(BindAddr));
+		BindAddr.type = NETTYPE_ALL;
+		BindAddr.port = g_Config.m_EcPort;
+	}
+
+	if(m_NetConsole.Open(BindAddr, 0))
+	{
+		m_NetConsole.SetCallbacks(NewClientCallback, DelClientCallback, this);
+		m_Ready = true;
+		char aBuf[128];
+		str_format(aBuf, sizeof(aBuf), "bound to %s:%d", g_Config.m_EcBindaddr, g_Config.m_EcPort);
+		Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD,"econ", aBuf);
+
+		Console()->Chain("ec_output_level", ConchainEconOutputLevelUpdate, this);
+		m_PrintCBIndex = Console()->RegisterPrintCallback(g_Config.m_EcOutputLevel, SendLineCB, this);
+	}
+	else
+		Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD,"econ", "couldn't open socket. port might already be in use");
+}
+
+void CEcon::Update()
+{
+	if(!m_Ready)
+		return;
+
+	m_NetConsole.Update();
+
+	char aBuf[NET_MAX_PACKETSIZE];
+	int ClientID;
+
+	while(m_NetConsole.Recv(aBuf, (int)(sizeof(aBuf))-1, &ClientID))
+	{
+		dbg_assert(m_aClients[ClientID].m_State != CClient::STATE_EMPTY, "got message from empty slot");
+		if(m_aClients[ClientID].m_State == CClient::STATE_CONNECTED)
+		{
+			if(str_comp(aBuf, g_Config.m_EcPassword) == 0)
+			{
+				m_aClients[ClientID].m_State = CClient::STATE_AUTHED;
+				m_NetConsole.Send(ClientID, "Authentication successful. External console access granted.");
+
+				str_format(aBuf, sizeof(aBuf), "cid=%d authed", ClientID);
+				Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "econ", aBuf);
+			}
+			else
+			{
+				m_aClients[ClientID].m_AuthTries++;
+				char aBuf[128];
+				str_format(aBuf, sizeof(aBuf), "Wrong password %d/%d.", m_aClients[ClientID].m_AuthTries, MAX_AUTH_TRIES);
+				m_NetConsole.Send(ClientID, aBuf);
+				if(m_aClients[ClientID].m_AuthTries >= MAX_AUTH_TRIES)
+				{
+					if(!g_Config.m_EcBantime)
+						m_NetConsole.Drop(ClientID, "Too many authentication tries");
+					else
+					{
+						NETADDR Addr = m_NetConsole.ClientAddr(ClientID);
+						m_NetConsole.AddBan(Addr, g_Config.m_EcBantime*60);
+					}
+				}
+			}
+		}
+		else if(m_aClients[ClientID].m_State == CClient::STATE_AUTHED)
+		{
+			char aFormatted[256];
+			str_format(aFormatted, sizeof(aBuf), "cid=%d cmd='%s'", ClientID, aBuf);
+			Console()->Print(IConsole::OUTPUT_LEVEL_ADDINFO, "server", aFormatted);
+			Console()->ExecuteLine(aBuf);
+		}
+	}
+
+	for(int i = 0; i < NET_MAX_CONSOLE_CLIENTS; ++i)
+	{
+		if(m_aClients[i].m_State == CClient::STATE_CONNECTED &&
+			time_get() > m_aClients[i].m_TimeConnected + g_Config.m_EcAuthTimeout * time_freq())
+			m_NetConsole.Drop(i, "authentication timeout");
+	}
+}
+
+void CEcon::Send(int ClientID, const char *pLine)
+{
+	if(!m_Ready)
+		return;
+
+	if(ClientID == -1)
+	{
+		for(int i = 0; i < NET_MAX_CONSOLE_CLIENTS; i++)
+		{
+			if(m_aClients[i].m_State == CClient::STATE_AUTHED)
+				m_NetConsole.Send(i, pLine);
+		}
+	}
+	else if(ClientID >= 0 && ClientID < NET_MAX_CONSOLE_CLIENTS && m_aClients[ClientID].m_State == CClient::STATE_AUTHED)
+		m_NetConsole.Send(ClientID, pLine);
+}
+
+void CEcon::Shutdown()
+{
+	if(!m_Ready)
+		return;
+
+	m_NetConsole.Close();
+}
diff --git a/src/engine/shared/econ.h b/src/engine/shared/econ.h
new file mode 100644
index 00000000..daec34c4
--- /dev/null
+++ b/src/engine/shared/econ.h
@@ -0,0 +1,50 @@
+#ifndef ENGINE_SHARED_ECON_H
+#define ENGINE_SHARED_ECON_H
+
+#include "network.h"
+
+class CEcon
+{
+	enum
+	{
+		MAX_AUTH_TRIES=3,
+	};
+
+	class CClient
+	{
+	public:
+		enum
+		{
+			STATE_EMPTY=0,
+			STATE_CONNECTED,
+			STATE_AUTHED,
+		};
+
+		int m_State;
+		int64 m_TimeConnected;
+		int m_AuthTries;
+	};
+	CClient m_aClients[NET_MAX_CONSOLE_CLIENTS];
+
+	IConsole *m_pConsole;
+	CNetConsole m_NetConsole;
+
+	bool m_Ready;
+	int m_PrintCBIndex;
+
+	static void SendLineCB(const char *pLine, void *pUserData);
+	static void ConchainEconOutputLevelUpdate(IConsole::IResult *pResult, void *pUserData, IConsole::FCommandCallback pfnCallback, void *pCallbackUserData);
+
+	static int NewClientCallback(int ClientID, void *pUser);
+	static int DelClientCallback(int ClientID, const char *pReason, void *pUser);
+
+public:
+	IConsole *Console() { return m_pConsole; }
+
+	void Init(IConsole *pConsole);
+	void Update();
+	void Send(int ClientID, const char *pLine);
+	void Shutdown();
+};
+
+#endif
diff --git a/src/engine/shared/filecollection.cpp b/src/engine/shared/filecollection.cpp
new file mode 100644
index 00000000..622534f2
--- /dev/null
+++ b/src/engine/shared/filecollection.cpp
@@ -0,0 +1,186 @@
+/* (c) Magnus Auvinen. See licence.txt in the root of the distribution for more information. */
+/* If you are missing that file, acquire a complete release at teeworlds.com.                */
+
+#include <base/math.h>
+
+#include <engine/storage.h>
+
+#include "filecollection.h"
+
+bool CFileCollection::IsFilenameValid(const char *pFilename)
+{
+	if(str_length(pFilename) != m_FileDescLength+TIMESTAMP_LENGTH+m_FileExtLength ||
+		str_comp_num(pFilename, m_aFileDesc, m_FileDescLength) ||
+		str_comp(pFilename+m_FileDescLength+TIMESTAMP_LENGTH, m_aFileExt))
+		return false;
+
+	pFilename += m_FileDescLength;
+	if(pFilename[0] == '_' &&
+		pFilename[1] >= '0' && pFilename[1] <= '9' &&
+		pFilename[2] >= '0' && pFilename[2] <= '9' &&
+		pFilename[3] >= '0' && pFilename[3] <= '9' &&
+		pFilename[4] >= '0' && pFilename[4] <= '9' &&
+		pFilename[5] == '-' &&
+		pFilename[6] >= '0' && pFilename[6] <= '9' &&
+		pFilename[7] >= '0' && pFilename[7] <= '9' &&
+		pFilename[8] == '-' &&
+		pFilename[9] >= '0' && pFilename[9] <= '9' &&
+		pFilename[10] >= '0' && pFilename[10] <= '9' &&
+		pFilename[11] == '_' &&
+		pFilename[12] >= '0' && pFilename[12] <= '9' &&
+		pFilename[13] >= '0' && pFilename[13] <= '9' &&
+		pFilename[14] == '-' &&
+		pFilename[15] >= '0' && pFilename[15] <= '9' &&
+		pFilename[16] >= '0' && pFilename[16] <= '9' &&
+		pFilename[17] == '-' &&
+		pFilename[18] >= '0' && pFilename[18] <= '9' &&
+		pFilename[19] >= '0' && pFilename[19] <= '9')
+		return true;
+
+	return false;
+}
+
+int64 CFileCollection::ExtractTimestamp(const char *pTimestring)
+{
+	int64 Timestamp = pTimestring[0]-'0'; Timestamp <<= 4;
+	Timestamp += pTimestring[1]-'0'; Timestamp <<= 4;
+	Timestamp += pTimestring[2]-'0'; Timestamp <<= 4;
+	Timestamp += pTimestring[3]-'0'; Timestamp <<= 4;
+	Timestamp += pTimestring[5]-'0'; Timestamp <<= 4;
+	Timestamp += pTimestring[6]-'0'; Timestamp <<= 4;
+	Timestamp += pTimestring[8]-'0'; Timestamp <<= 4;
+	Timestamp += pTimestring[9]-'0'; Timestamp <<= 4;
+	Timestamp += pTimestring[11]-'0'; Timestamp <<= 4;
+	Timestamp += pTimestring[12]-'0'; Timestamp <<= 4;
+	Timestamp += pTimestring[14]-'0'; Timestamp <<= 4;
+	Timestamp += pTimestring[15]-'0'; Timestamp <<= 4;
+	Timestamp += pTimestring[17]-'0'; Timestamp <<= 4;
+	Timestamp += pTimestring[18]-'0';
+
+	return Timestamp;
+}
+
+void CFileCollection::BuildTimestring(int64 Timestamp, char *pTimestring)
+{
+	pTimestring[19] = 0;
+	pTimestring[18] = (Timestamp&0xF)+'0'; Timestamp >>= 4;
+	pTimestring[17] = (Timestamp&0xF)+'0'; Timestamp >>= 4;
+	pTimestring[16] = '-';
+	pTimestring[15] = (Timestamp&0xF)+'0'; Timestamp >>= 4;
+	pTimestring[14] = (Timestamp&0xF)+'0'; Timestamp >>= 4;
+	pTimestring[13] = '-';
+	pTimestring[12] = (Timestamp&0xF)+'0'; Timestamp >>= 4;
+	pTimestring[11] = (Timestamp&0xF)+'0'; Timestamp >>= 4;
+	pTimestring[10] = '_';
+	pTimestring[9] = (Timestamp&0xF)+'0'; Timestamp >>= 4;
+	pTimestring[8] = (Timestamp&0xF)+'0'; Timestamp >>= 4;
+	pTimestring[7] = '-';
+	pTimestring[6] = (Timestamp&0xF)+'0'; Timestamp >>= 4;
+	pTimestring[5] = (Timestamp&0xF)+'0'; Timestamp >>= 4;
+	pTimestring[4] = '-';
+	pTimestring[3] = (Timestamp&0xF)+'0'; Timestamp >>= 4;
+	pTimestring[2] = (Timestamp&0xF)+'0'; Timestamp >>= 4;
+	pTimestring[1] = (Timestamp&0xF)+'0'; Timestamp >>= 4;
+	pTimestring[0] = (Timestamp&0xF)+'0';
+}
+
+void CFileCollection::Init(IStorage *pStorage, const char *pPath, const char *pFileDesc, const char *pFileExt, int MaxEntries)
+{
+	mem_zero(m_aTimestamps, sizeof(m_aTimestamps));
+	m_NumTimestamps = 0;
+	m_MaxEntries = clamp(MaxEntries, 1, static_cast<int>(MAX_ENTRIES));
+	str_copy(m_aFileDesc, pFileDesc, sizeof(m_aFileDesc));
+	m_FileDescLength = str_length(m_aFileDesc);
+	str_copy(m_aFileExt, pFileExt, sizeof(m_aFileExt));
+	m_FileExtLength = str_length(m_aFileExt);
+	str_copy(m_aPath, pPath, sizeof(m_aPath));
+	m_pStorage = pStorage;
+
+	m_pStorage->ListDirectory(IStorage::TYPE_SAVE, m_aPath, FilelistCallback, this);
+}
+
+void CFileCollection::AddEntry(int64 Timestamp)
+{
+	if(m_NumTimestamps == 0)
+	{
+		// empty list
+		m_aTimestamps[m_NumTimestamps++] = Timestamp;
+	}
+	else
+	{
+		// remove old file
+		if(m_NumTimestamps == m_MaxEntries)
+		{
+			char aBuf[512];
+			char aTimestring[TIMESTAMP_LENGTH];
+			BuildTimestring(m_aTimestamps[0], aTimestring);
+			str_format(aBuf, sizeof(aBuf), "%s/%s_%s%s", m_aPath, m_aFileDesc, aTimestring, m_aFileExt);
+			m_pStorage->RemoveFile(aBuf, IStorage::TYPE_SAVE);
+		}
+
+		// add entry to the sorted list
+		if(m_aTimestamps[0] > Timestamp)
+		{
+			// first entry
+			if(m_NumTimestamps < m_MaxEntries)
+			{
+				mem_move(m_aTimestamps+1, m_aTimestamps, m_NumTimestamps*sizeof(int64));
+				m_aTimestamps[0] = Timestamp;
+				++m_NumTimestamps;
+			}
+		}
+		else if(m_aTimestamps[m_NumTimestamps-1] <= Timestamp)
+		{
+			// last entry
+			if(m_NumTimestamps == m_MaxEntries)
+			{
+				mem_move(m_aTimestamps, m_aTimestamps+1, (m_NumTimestamps-1)*sizeof(int64));
+				m_aTimestamps[m_NumTimestamps-1] = Timestamp;
+			}
+			else
+				m_aTimestamps[m_NumTimestamps++] = Timestamp;
+		}
+		else
+		{
+			// middle entry
+			int Left = 0, Right = m_NumTimestamps-1;
+			while(Right-Left > 1)
+			{
+				int Mid = (Left+Right)/2;
+				if(m_aTimestamps[Mid] > Timestamp)
+					Right = Mid;
+				else
+					Left = Mid;
+			}
+
+			if(m_NumTimestamps == m_MaxEntries)
+			{
+				mem_move(m_aTimestamps, m_aTimestamps+1, (Right-1)*sizeof(int64));
+				m_aTimestamps[Right-1] = Timestamp;
+			}
+			else
+			{
+				mem_move(m_aTimestamps+Right+1, m_aTimestamps+Right, (m_NumTimestamps-Right)*sizeof(int64));
+				m_aTimestamps[Right] = Timestamp;
+				++m_NumTimestamps;
+			}
+		}
+	}
+}
+
+int CFileCollection::FilelistCallback(const char *pFilename, int IsDir, int StorageType, void *pUser)
+{
+	CFileCollection *pThis = static_cast<CFileCollection *>(pUser);
+
+	// check for valid file name format
+	if(IsDir || !pThis->IsFilenameValid(pFilename))
+		return 0;
+
+	// extract the timestamp
+	int64 Timestamp = pThis->ExtractTimestamp(pFilename+pThis->m_FileDescLength+1);
+
+	// add the entry
+	pThis->AddEntry(Timestamp);
+
+	return 0;
+}
diff --git a/src/engine/shared/filecollection.h b/src/engine/shared/filecollection.h
new file mode 100644
index 00000000..ac633892
--- /dev/null
+++ b/src/engine/shared/filecollection.h
@@ -0,0 +1,35 @@
+/* (c) Magnus Auvinen. See licence.txt in the root of the distribution for more information. */
+/* If you are missing that file, acquire a complete release at teeworlds.com.                */
+#ifndef ENGINE_SHARED_FILECOLLECTION_H
+#define ENGINE_SHARED_FILECOLLECTION_H
+
+class CFileCollection
+{
+	enum
+	{
+		MAX_ENTRIES=1000,
+		TIMESTAMP_LENGTH=20,	// _YYYY-MM-DD_HH-MM-SS
+	};
+
+	int64 m_aTimestamps[MAX_ENTRIES];
+	int m_NumTimestamps;
+	int m_MaxEntries;
+	char m_aFileDesc[128];
+	int m_FileDescLength;
+	char m_aFileExt[32];
+	int m_FileExtLength;
+	char m_aPath[512];
+	IStorage *m_pStorage;
+
+	bool IsFilenameValid(const char *pFilename);
+	int64 ExtractTimestamp(const char *pTimestring);
+	void BuildTimestring(int64 Timestamp, char *pTimestring);
+
+public:
+	void Init(IStorage *pStorage, const char *pPath, const char *pFileDesc, const char *pFileExt, int MaxEntries);
+	void AddEntry(int64 Timestamp);
+
+	static int FilelistCallback(const char *pFilename, int IsDir, int StorageType, void *pUser);
+};
+
+#endif
diff --git a/src/engine/shared/masterserver.cpp b/src/engine/shared/masterserver.cpp
index 1bf402ca..1271eeaf 100644
--- a/src/engine/shared/masterserver.cpp
+++ b/src/engine/shared/masterserver.cpp
@@ -21,51 +21,57 @@ public:
 		bool m_Valid;
 
 		CHostLookup m_Lookup;
-	} ;
+	};
+
+	enum
+	{
+		STATE_INIT,
+		STATE_UPDATE,
+		STATE_READY,
+	};
 
 	CMasterInfo m_aMasterServers[MAX_MASTERSERVERS];
-	int m_NeedsUpdate;
+	int m_State;
 	IEngine *m_pEngine;
 	IStorage *m_pStorage;
 
 	CMasterServer()
 	{
 		SetDefault();
-		m_NeedsUpdate = -1;
+		m_State = STATE_INIT;
 		m_pEngine = 0;
+		m_pStorage = 0;
 	}
 
 	virtual int RefreshAddresses(int Nettype)
 	{
-		int i;
-
-		if(m_NeedsUpdate != -1)
-			return 0;
+		if(m_State != STATE_INIT)
+			return -1;
 
 		dbg_msg("engine/mastersrv", "refreshing master server addresses");
 
 		// add lookup jobs
-		for(i = 0; i < MAX_MASTERSERVERS; i++)
+		for(int i = 0; i < MAX_MASTERSERVERS; i++)
 		{
 			m_pEngine->HostLookup(&m_aMasterServers[i].m_Lookup, m_aMasterServers[i].m_aHostname, Nettype);
 			m_aMasterServers[i].m_Valid = false;
 		}
 
-		m_NeedsUpdate = 1;
+		m_State = STATE_UPDATE;
 		return 0;
 	}
 
 	virtual void Update()
 	{
 		// check if we need to update
-		if(m_NeedsUpdate != 1)
+		if(m_State != STATE_UPDATE)
 			return;
-		m_NeedsUpdate = 0;
+		m_State = STATE_READY;
 
 		for(int i = 0; i < MAX_MASTERSERVERS; i++)
 		{
 			if(m_aMasterServers[i].m_Lookup.m_Job.Status() != CJob::STATE_DONE)
-				m_NeedsUpdate = 1;
+				m_State = STATE_UPDATE;
 			else
 			{
 				if(m_aMasterServers[i].m_Lookup.m_Job.Result() == 0)
@@ -79,7 +85,7 @@ public:
 			}
 		}
 
-		if(!m_NeedsUpdate)
+		if(m_State == STATE_READY)
 		{
 			dbg_msg("engine/mastersrv", "saving addresses");
 			Save();
@@ -88,7 +94,7 @@ public:
 
 	virtual int IsRefreshing()
 	{
-		return m_NeedsUpdate;
+		return m_State != STATE_READY;
 	}
 
 	virtual NETADDR GetAddr(int Index)
@@ -106,16 +112,6 @@ public:
 		return m_aMasterServers[Index].m_Valid;
 	}
 
-	virtual void DumpServers()
-	{
-		for(int i = 0; i < MAX_MASTERSERVERS; i++)
-		{
-			char aAddrStr[NETADDR_MAXSTRSIZE];
-			net_addr_str(&m_aMasterServers[i].m_Addr, aAddrStr, sizeof(aAddrStr));
-			dbg_msg("mastersrv", "#%d = %s", i, aAddrStr);
-		}
-	}
-
 	virtual void Init()
 	{
 		m_pEngine = Kernel()->RequestInterface<IEngine>();
@@ -131,17 +127,15 @@ public:
 
 	virtual int Load()
 	{
-		CLineReader LineReader;
-		IOHANDLE File;
-		int Count = 0;
 		if(!m_pStorage)
 			return -1;
 
 		// try to open file
-		File = m_pStorage->OpenFile("masters.cfg", IOFLAG_READ, IStorage::TYPE_SAVE);
+		IOHANDLE File = m_pStorage->OpenFile("masters.cfg", IOFLAG_READ, IStorage::TYPE_SAVE);
 		if(!File)
 			return -1;
 
+		CLineReader LineReader;
 		LineReader.Init(File);
 		while(1)
 		{
@@ -152,19 +146,32 @@ public:
 
 			// parse line
 			char aAddrStr[NETADDR_MAXSTRSIZE];
-			if(sscanf(pLine, "%s %s", Info.m_aHostname, aAddrStr) == 2 && net_addr_from_str(&Info.m_Addr, aAddrStr) == 0)
+			if(sscanf(pLine, "%127s %47s", Info.m_aHostname, aAddrStr) == 2 && net_addr_from_str(&Info.m_Addr, aAddrStr) == 0)
 			{
 				Info.m_Addr.port = 8300;
-				if(Count != MAX_MASTERSERVERS)
+				bool Added = false;
+				for(int i = 0; i < MAX_MASTERSERVERS; ++i)
+					if(str_comp(m_aMasterServers[i].m_aHostname, Info.m_aHostname) == 0)
+					{
+						m_aMasterServers[i] = Info;
+						Added = true;
+						break;
+					}
+				
+				if(!Added)
 				{
-					m_aMasterServers[Count] = Info;
-					Count++;
+					for(int i = 0; i < MAX_MASTERSERVERS; ++i)
+						if(m_aMasterServers[i].m_Addr.type == NETTYPE_INVALID)
+						{
+							m_aMasterServers[i] = Info;
+							Added = true;
+							break;
+						}
 				}
-				//else
-				//	dbg_msg("engine/mastersrv", "warning: skipped master server '%s' due to limit of %d", pLine, MAX_MASTERSERVERS);
+
+				if(!Added)
+					break;
 			}
-			//else
-			//	dbg_msg("engine/mastersrv", "warning: couldn't parse master server '%s'", pLine);
 		}
 
 		io_close(File);
@@ -173,21 +180,22 @@ public:
 
 	virtual int Save()
 	{
-		IOHANDLE File;
-
 		if(!m_pStorage)
 			return -1;
 
 		// try to open file
-		File = m_pStorage->OpenFile("masters.cfg", IOFLAG_WRITE, IStorage::TYPE_SAVE);
+		IOHANDLE File = m_pStorage->OpenFile("masters.cfg", IOFLAG_WRITE, IStorage::TYPE_SAVE);
 		if(!File)
 			return -1;
 
 		for(int i = 0; i < MAX_MASTERSERVERS; i++)
 		{
 			char aAddrStr[NETADDR_MAXSTRSIZE];
-			net_addr_str(&m_aMasterServers[i].m_Addr, aAddrStr, sizeof(aAddrStr));
-			char aBuf[1024];
+			if(m_aMasterServers[i].m_Addr.type != NETTYPE_INVALID)
+				net_addr_str(&m_aMasterServers[i].m_Addr, aAddrStr, sizeof(aAddrStr));
+			else
+				aAddrStr[0] = 0;
+			char aBuf[256];
 			str_format(aBuf, sizeof(aBuf), "%s %s\n", m_aMasterServers[i].m_aHostname, aAddrStr);
 
 			io_write(File, aBuf, str_length(aBuf));
diff --git a/src/engine/shared/network.h b/src/engine/shared/network.h
index 425d970a..d10c03b6 100644
--- a/src/engine/shared/network.h
+++ b/src/engine/shared/network.h
@@ -49,6 +49,7 @@ enum
 	NET_MAX_CHUNKHEADERSIZE = 5,
 	NET_PACKETHEADERSIZE = 3,
 	NET_MAX_CLIENTS = 16,
+	NET_MAX_CONSOLE_CLIENTS = 4,
 	NET_MAX_SEQUENCE = 1<<10,
 	NET_SEQUENCE_MASK = NET_MAX_SEQUENCE-1,
 
@@ -192,6 +193,36 @@ public:
 	int AckSequence() const { return m_Ack; }
 };
 
+class CConsoleNetConnection
+{
+private:
+	int m_State;
+
+	NETADDR m_PeerAddr;
+	NETSOCKET m_Socket;
+
+	char m_aBuffer[NET_MAX_PACKETSIZE];
+	int m_BufferOffset;
+
+	char m_aErrorString[256];
+
+	bool m_LineEndingDetected;
+	char m_aLineEnding[3];
+
+public:
+	void Init(NETSOCKET Socket, const NETADDR *pAddr);
+	void Disconnect(const char *pReason);
+
+	int State() const { return m_State; }
+	NETADDR PeerAddress() const { return m_PeerAddr; }
+	const char *ErrorString() const { return m_aErrorString; }
+
+	void Reset();
+	int Update();
+	int Send(const char *pLine);
+	int Recv(char *pLine, int MaxLength);
+};
+
 class CNetRecvUnpacker
 {
 public:
@@ -285,12 +316,66 @@ public:
 	// status requests
 	NETADDR ClientAddr(int ClientID) const { return m_aSlots[ClientID].m_Connection.PeerAddress(); }
 	NETSOCKET Socket() const { return m_Socket; }
+	int NetType() { return m_Socket.type; }
 	int MaxClients() const { return m_MaxClients; }
 
 	//
 	void SetMaxClientsPerIP(int Max);
 };
 
+class CNetConsole
+{
+	enum
+	{
+		MAX_BANS=128,
+	};
+
+	int FindBan(NETADDR Addr);
+	void UpdateBans();
+
+	struct CBanEntry
+	{
+		NETADDR m_Addr;
+		int m_Expires;
+	} m_aBans[MAX_BANS];
+	int m_NumBans;
+
+	struct CSlot
+	{
+		CConsoleNetConnection m_Connection;
+	};
+
+	NETSOCKET m_Socket;
+	CSlot m_aSlots[NET_MAX_CONSOLE_CLIENTS];
+
+	NETFUNC_NEWCLIENT m_pfnNewClient;
+	NETFUNC_DELCLIENT m_pfnDelClient;
+	void *m_UserPtr;
+
+	CNetRecvUnpacker m_RecvUnpacker;
+
+public:
+	void SetCallbacks(NETFUNC_NEWCLIENT pfnNewClient, NETFUNC_DELCLIENT pfnDelClient, void *pUser);
+
+	//
+	bool Open(NETADDR BindAddr, int Flags);
+	int Close();
+
+	//
+	int Recv(char *pLine, int MaxLength, int *pClientID = 0);
+	int Send(int ClientID, const char *pLine);
+	int Update();
+
+	//
+	int AcceptClient(NETSOCKET Socket, const NETADDR *pAddr);
+	int Drop(int ClientID, const char *pReason);
+
+	bool AddBan(NETADDR Addr, int Seconds);
+
+	// status requests
+	NETADDR ClientAddr(int ClientID) const { return m_aSlots[ClientID].m_Connection.PeerAddress(); }
+};
+
 
 
 // client side
@@ -320,6 +405,7 @@ public:
 	int ResetErrorString();
 
 	// error and state
+	int NetType() { return m_Socket.type; }
 	int State();
 	int GotProblems();
 	const char *ErrorString();
diff --git a/src/engine/shared/network_console.cpp b/src/engine/shared/network_console.cpp
new file mode 100644
index 00000000..13ed3751
--- /dev/null
+++ b/src/engine/shared/network_console.cpp
@@ -0,0 +1,219 @@
+/* (c) Magnus Auvinen. See licence.txt in the root of the distribution for more information. */
+/* If you are missing that file, acquire a complete release at teeworlds.com.                */
+#include <base/system.h>
+#include "network.h"
+
+bool CNetConsole::Open(NETADDR BindAddr, int Flags)
+{
+	// zero out the whole structure
+	mem_zero(this, sizeof(*this));
+	m_Socket.type = NETTYPE_INVALID;
+	m_Socket.ipv4sock = -1;
+	m_Socket.ipv6sock = -1;
+
+	// open socket
+	m_Socket = net_tcp_create(BindAddr);
+	if(!m_Socket.type)
+		return false;
+	if(net_tcp_listen(m_Socket, NET_MAX_CONSOLE_CLIENTS))
+		return false;
+	net_set_non_blocking(m_Socket);
+
+	for(int i = 0; i < NET_MAX_CONSOLE_CLIENTS; i++)
+		m_aSlots[i].m_Connection.Reset();
+
+	return true;
+}
+
+void CNetConsole::SetCallbacks(NETFUNC_NEWCLIENT pfnNewClient, NETFUNC_DELCLIENT pfnDelClient, void *pUser)
+{
+	m_pfnNewClient = pfnNewClient;
+	m_pfnDelClient = pfnDelClient;
+	m_UserPtr = pUser;
+}
+
+int CNetConsole::Close()
+{
+	for(int i = 0; i < NET_MAX_CONSOLE_CLIENTS; i++)
+		m_aSlots[i].m_Connection.Disconnect("closing console");
+
+	net_tcp_close(m_Socket);
+
+	return 0;
+}
+
+int CNetConsole::Drop(int ClientID, const char *pReason)
+{
+	if(m_pfnDelClient)
+		m_pfnDelClient(ClientID, pReason, m_UserPtr);
+
+	m_aSlots[ClientID].m_Connection.Disconnect(pReason);
+
+	return 0;
+}
+
+int CNetConsole::AcceptClient(NETSOCKET Socket, const NETADDR *pAddr)
+{
+	char aError[256] = { 0 };
+	int FreeSlot = -1;
+	
+	// look for free slot or multiple client
+	for(int i = 0; i < NET_MAX_CONSOLE_CLIENTS; i++)
+	{
+		if(FreeSlot == -1 && m_aSlots[i].m_Connection.State() == NET_CONNSTATE_OFFLINE)
+			FreeSlot = i;
+		if(m_aSlots[i].m_Connection.State() != NET_CONNSTATE_OFFLINE)
+		{
+			NETADDR PeerAddr = m_aSlots[i].m_Connection.PeerAddress();
+			if(net_addr_comp(pAddr, &PeerAddr) == 0)
+			{
+				str_copy(aError, "only one client per IP allowed", sizeof(aError));
+				break;
+			}
+		}
+	}
+
+	// accept client
+	if(!aError[0] && FreeSlot != -1)
+	{
+		m_aSlots[FreeSlot].m_Connection.Init(Socket, pAddr);
+		if(m_pfnNewClient)
+			m_pfnNewClient(FreeSlot, m_UserPtr);
+		return 0;
+	}
+
+	// reject client
+	if(!aError[0])
+		str_copy(aError, "no free slot available", sizeof(aError));
+
+	net_tcp_send(Socket, aError, str_length(aError));
+	net_tcp_close(Socket);
+
+	return -1;
+}
+
+int CNetConsole::Update()
+{
+	NETSOCKET Socket;
+	NETADDR Addr;
+
+	if(net_tcp_accept(m_Socket, &Socket, &Addr) > 0)
+	{
+		int Index = FindBan(Addr);
+		if(Index == -1)
+			AcceptClient(Socket, &Addr);
+		else
+		{
+			char aBuf[128];
+			if(m_aBans[Index].m_Expires > -1)
+			{
+				int Mins = (m_aBans[Index].m_Expires-time_timestamp()+ 59) / 60;
+				if(Mins <= 1)
+					str_format(aBuf, sizeof(aBuf), "You have been banned for 1 minute");
+				else
+					str_format(aBuf, sizeof(aBuf), "You have been banned for %d minutes", Mins);
+			}
+			else
+				str_format(aBuf, sizeof(aBuf), "You have been banned for life");
+			
+			net_tcp_send(Socket, aBuf, str_length(aBuf));
+			net_tcp_close(Socket);
+		}
+	}
+
+	for(int i = 0; i < NET_MAX_CONSOLE_CLIENTS; i++)
+	{
+		if(m_aSlots[i].m_Connection.State() == NET_CONNSTATE_ONLINE)
+			m_aSlots[i].m_Connection.Update();
+		if(m_aSlots[i].m_Connection.State() == NET_CONNSTATE_ERROR)
+			Drop(i, m_aSlots[i].m_Connection.ErrorString());
+	}
+
+	UpdateBans();
+
+	return 0;
+}
+
+int CNetConsole::Recv(char *pLine, int MaxLength, int *pClientID)
+{
+	for(int i = 0; i < NET_MAX_CONSOLE_CLIENTS; i++)
+	{
+		if(m_aSlots[i].m_Connection.State() == NET_CONNSTATE_ONLINE && m_aSlots[i].m_Connection.Recv(pLine, MaxLength))
+		{
+			if(pClientID)
+				*pClientID = i;
+			return 1;
+		}
+	}
+	return 0;
+}
+
+int CNetConsole::Send(int ClientID, const char *pLine)
+{
+	if(m_aSlots[ClientID].m_Connection.State() == NET_CONNSTATE_ONLINE)
+		return m_aSlots[ClientID].m_Connection.Send(pLine);
+	else
+		return -1;
+}
+
+int CNetConsole::FindBan(NETADDR Addr)
+{
+	Addr.port = 0;
+	for(int i = 0; i < m_NumBans; i++)
+		if(net_addr_comp(&m_aBans[i].m_Addr, &Addr) == 0)
+			return i;
+
+	return -1;
+}
+
+bool CNetConsole::AddBan(NETADDR Addr, int Seconds)
+{
+	if(m_NumBans == MAX_BANS)
+		return false;
+	
+	Addr.port = 0;
+	int Index = FindBan(Addr);
+	if(Index == -1)
+	{
+		Index = m_NumBans++;
+		m_aBans[Index].m_Addr = Addr;
+	}
+	m_aBans[Index].m_Expires = Seconds>0 ? time_timestamp()+Seconds : -1;
+
+	for(int i = 0; i < NET_MAX_CONSOLE_CLIENTS; i++)
+	{
+		if(m_aSlots[i].m_Connection.State() != NET_CONNSTATE_OFFLINE)
+		{
+			NETADDR PeerAddr = m_aSlots[i].m_Connection.PeerAddress();
+			PeerAddr.port = 0;
+			if(net_addr_comp(&Addr, &PeerAddr) == 0)
+			{
+				char aBuf[128];
+				if(Seconds>0)
+				{
+					int Mins = (Seconds + 59) / 60;
+					if(Mins <= 1)
+						str_format(aBuf, sizeof(aBuf), "You have been banned for 1 minute");
+					else
+						str_format(aBuf, sizeof(aBuf), "You have been banned for %d minutes", Mins);
+				}
+				else
+					str_format(aBuf, sizeof(aBuf), "You have been banned for life");
+				Drop(i, aBuf);
+			}
+		}
+	}
+	return true;
+}
+
+void CNetConsole::UpdateBans()
+{
+	int Now = time_timestamp();
+	for(int i = 0; i < m_NumBans; ++i)
+		if(m_aBans[i].m_Expires > 0 && m_aBans[i].m_Expires < Now)
+		{
+			m_aBans[i] = m_aBans[m_NumBans-1];
+			--m_NumBans;
+			break;
+		}
+}
diff --git a/src/engine/shared/network_console_conn.cpp b/src/engine/shared/network_console_conn.cpp
new file mode 100644
index 00000000..75b581fa
--- /dev/null
+++ b/src/engine/shared/network_console_conn.cpp
@@ -0,0 +1,186 @@
+/* (c) Magnus Auvinen. See licence.txt in the root of the distribution for more information. */
+/* If you are missing that file, acquire a complete release at teeworlds.com.                */
+#include <base/system.h>
+#include "network.h"
+
+void CConsoleNetConnection::Reset()
+{
+	m_State = NET_CONNSTATE_OFFLINE;
+	mem_zero(&m_PeerAddr, sizeof(m_PeerAddr));
+	m_aErrorString[0] = 0;
+
+	m_Socket.type = NETTYPE_INVALID;
+	m_Socket.ipv4sock = -1;
+	m_Socket.ipv6sock = -1;
+	m_aBuffer[0] = 0;
+	m_BufferOffset = 0;
+
+	m_LineEndingDetected = false;
+	#if defined(CONF_FAMILY_WINDOWS)
+		m_aLineEnding[0] = '\r';
+		m_aLineEnding[1] = '\n';
+		m_aLineEnding[2] = 0;
+	#else
+		m_aLineEnding[0] = '\n';
+		m_aLineEnding[1] = 0;
+		m_aLineEnding[2] = 0;
+	#endif
+}
+
+void CConsoleNetConnection::Init(NETSOCKET Socket, const NETADDR *pAddr)
+{
+	Reset();
+
+	m_Socket = Socket;
+	net_set_non_blocking(m_Socket);
+
+	m_PeerAddr = *pAddr;
+	m_State = NET_CONNSTATE_ONLINE;
+}
+
+void CConsoleNetConnection::Disconnect(const char *pReason)
+{
+	if(State() == NET_CONNSTATE_OFFLINE)
+		return;
+
+	if(pReason && pReason[0])
+		Send(pReason);
+
+	net_tcp_close(m_Socket);
+
+	Reset();
+}
+
+int CConsoleNetConnection::Update()
+{
+	if(State() == NET_CONNSTATE_ONLINE)
+	{
+		if((int)(sizeof(m_aBuffer)) <= m_BufferOffset)
+		{
+			m_State = NET_CONNSTATE_ERROR;
+			str_copy(m_aErrorString, "too weak connection (out of buffer)", sizeof(m_aErrorString));
+			return -1;
+		}
+
+		int Bytes = net_tcp_recv(m_Socket, m_aBuffer+m_BufferOffset, (int)(sizeof(m_aBuffer))-m_BufferOffset);
+
+		if(Bytes > 0)
+		{
+			m_BufferOffset += Bytes;
+		}
+		else if(Bytes < 0)
+		{
+			if(net_would_block()) // no data received
+				return 0;
+
+			m_State = NET_CONNSTATE_ERROR; // error
+			str_copy(m_aErrorString, "connection failure", sizeof(m_aErrorString));
+			return -1;
+		}
+		else
+		{
+			m_State = NET_CONNSTATE_ERROR;
+			str_copy(m_aErrorString, "remote end closed the connection", sizeof(m_aErrorString));
+			return -1;
+		}
+	}
+
+	return 0;
+}
+
+int CConsoleNetConnection::Recv(char *pLine, int MaxLength)
+{
+	if(State() == NET_CONNSTATE_ONLINE)
+	{
+		if(m_BufferOffset)
+		{
+			// find message start
+			int StartOffset = 0;
+			while(m_aBuffer[StartOffset] == '\r' || m_aBuffer[StartOffset] == '\n')
+			{
+				// detect clients line ending format
+				if(!m_LineEndingDetected)
+				{
+					m_aLineEnding[0] = m_aBuffer[StartOffset];
+					if(StartOffset+1 < m_BufferOffset && (m_aBuffer[StartOffset+1] == '\r' || m_aBuffer[StartOffset+1] == '\n') &&
+						m_aBuffer[StartOffset] != m_aBuffer[StartOffset+1])
+						m_aLineEnding[1] = m_aBuffer[StartOffset+1];
+					m_LineEndingDetected = true;
+				}
+
+				if(++StartOffset >= m_BufferOffset)
+				{
+					m_BufferOffset = 0;
+					return 0;
+				}
+			}
+
+			// find message end
+			int EndOffset = StartOffset;
+			while(m_aBuffer[EndOffset] != '\r' && m_aBuffer[EndOffset] != '\n')
+			{
+				if(++EndOffset >= m_BufferOffset)
+				{
+					if(StartOffset > 0)
+					{
+						mem_move(m_aBuffer, m_aBuffer+StartOffset, m_BufferOffset-StartOffset);
+						m_BufferOffset -= StartOffset;
+					}
+					return 0;
+				}
+			}
+
+			// extract message and update buffer
+			if(MaxLength-1 < EndOffset-StartOffset)
+			{
+				if(StartOffset > 0)
+				{
+					mem_move(m_aBuffer, m_aBuffer+StartOffset, m_BufferOffset-StartOffset);
+					m_BufferOffset -= StartOffset;
+				}
+				return 0;
+			}
+			mem_copy(pLine, m_aBuffer+StartOffset, EndOffset-StartOffset);
+			pLine[EndOffset-StartOffset] = 0;
+			str_sanitize_cc(pLine);
+			mem_move(m_aBuffer, m_aBuffer+EndOffset, m_BufferOffset-EndOffset);
+			m_BufferOffset -= EndOffset;
+			return 1;
+		}
+	}
+	return 0;
+}
+
+int CConsoleNetConnection::Send(const char *pLine)
+{
+	if(State() != NET_CONNSTATE_ONLINE)
+		return -1;
+
+	char aBuf[1024];
+	str_copy(aBuf, pLine, (int)(sizeof(aBuf))-2);
+	int Length = str_length(aBuf);
+	aBuf[Length] = m_aLineEnding[0];
+	aBuf[Length+1] = m_aLineEnding[1];
+	aBuf[Length+2] = m_aLineEnding[2];
+	Length += 3;
+	const char *pData = aBuf;
+
+	while(true)
+	{
+		int Send = net_tcp_send(m_Socket, pData, Length);
+		if(Send < 0)
+		{
+			m_State = NET_CONNSTATE_ERROR;
+			str_copy(m_aErrorString, "failed to send packet", sizeof(m_aErrorString));
+			return -1;
+		}
+
+		if(Send >= Length)
+			break;
+
+		pData += Send;
+		Length -= Send;
+	}
+	
+	return 0;
+}
diff --git a/src/engine/shared/network_server.cpp b/src/engine/shared/network_server.cpp
index f3fbfa32..b100e1a2 100644
--- a/src/engine/shared/network_server.cpp
+++ b/src/engine/shared/network_server.cpp
@@ -221,10 +221,10 @@ int CNetServer::BanAdd(NETADDR Addr, int Seconds, const char *pReason)
 		char Buf[128];
 		NETADDR BanAddr;
 
-		int Mins = (Seconds + 59) / 60;
-		if(Mins)
+		if(Stamp > -1)
 		{
-			if(Mins == 1)
+			int Mins = (Seconds + 59) / 60;
+			if(Mins <= 1)
 				str_format(Buf, sizeof(Buf), "You have been banned for 1 minute (%s)", pReason);
 			else
 				str_format(Buf, sizeof(Buf), "You have been banned for %d minutes (%s)", Mins, pReason);
@@ -255,7 +255,7 @@ int CNetServer::Update()
 	}
 
 	// remove expired bans
-	while(m_BanPool_FirstUsed && m_BanPool_FirstUsed->m_Info.m_Expires < Now)
+	while(m_BanPool_FirstUsed && m_BanPool_FirstUsed->m_Info.m_Expires > -1 && m_BanPool_FirstUsed->m_Info.m_Expires < Now)
 	{
 		CBan *pBan = m_BanPool_FirstUsed;
 		BanRemoveByObject(pBan);
@@ -307,10 +307,10 @@ int CNetServer::Recv(CNetChunk *pChunk)
 			{
 				// banned, reply with a message
 				char BanStr[128];
-				if(pBan->m_Info.m_Expires)
+				if(pBan->m_Info.m_Expires > -1)
 				{
 					int Mins = ((pBan->m_Info.m_Expires - Now)+59)/60;
-					if(Mins == 1)
+					if(Mins <= 1)
 						str_format(BanStr, sizeof(BanStr), "Banned for 1 minute (%s)", pBan->m_Info.m_Reason);
 					else
 						str_format(BanStr, sizeof(BanStr), "Banned for %d minutes (%s)", Mins, pBan->m_Info.m_Reason);
diff --git a/src/engine/shared/protocol.h b/src/engine/shared/protocol.h
index 4a4895ad..ba04da8a 100644
--- a/src/engine/shared/protocol.h
+++ b/src/engine/shared/protocol.h
@@ -65,7 +65,11 @@ enum
 	// sent by both
 	NETMSG_PING,
 	NETMSG_PING_REPLY,
-	NETMSG_ERROR
+	NETMSG_ERROR,
+
+	// sent by server (todo: move it up)
+	NETMSG_RCON_CMD_ADD,
+	NETMSG_RCON_CMD_REM,
 };
 
 // this should be revised
diff --git a/src/game/client/components/console.cpp b/src/game/client/components/console.cpp
index 2f5c49ad..f2e9e65d 100644
--- a/src/game/client/components/console.cpp
+++ b/src/game/client/components/console.cpp
@@ -51,7 +51,7 @@ CGameConsole::CInstance::CInstance(int Type)
 	m_CompletionChosen = -1;
 	m_CompletionRenderOffset = 0.0f;
 
-	m_pCommand = 0x0;
+	m_IsCommand = false;
 }
 
 void CGameConsole::CInstance::Init(CGameConsole *pGameConsole)
@@ -147,14 +147,16 @@ void CGameConsole::CInstance::OnInput(IInput::CEvent Event)
 			{
 				m_CompletionChosen++;
 				m_CompletionEnumerationCount = 0;
-				m_pGameConsole->m_pConsole->PossibleCommands(m_aCompletionBuffer, m_CompletionFlagmask, PossibleCommandsCompleteCallback, this);
+				m_pGameConsole->m_pConsole->PossibleCommands(m_aCompletionBuffer, m_CompletionFlagmask, m_Type != CGameConsole::CONSOLETYPE_LOCAL &&
+					m_pGameConsole->Client()->RconAuthed() && m_pGameConsole->Client()->UseTempRconCommands(),	PossibleCommandsCompleteCallback, this);
 
 				// handle wrapping
 				if(m_CompletionEnumerationCount && m_CompletionChosen >= m_CompletionEnumerationCount)
 				{
 					m_CompletionChosen %= m_CompletionEnumerationCount;
 					m_CompletionEnumerationCount = 0;
-					m_pGameConsole->m_pConsole->PossibleCommands(m_aCompletionBuffer, m_CompletionFlagmask, PossibleCommandsCompleteCallback, this);
+					m_pGameConsole->m_pConsole->PossibleCommands(m_aCompletionBuffer, m_CompletionFlagmask, m_Type != CGameConsole::CONSOLETYPE_LOCAL &&
+						m_pGameConsole->Client()->RconAuthed() && m_pGameConsole->Client()->UseTempRconCommands(),	PossibleCommandsCompleteCallback, this);
 				}
 			}
 		}
@@ -190,7 +192,17 @@ void CGameConsole::CInstance::OnInput(IInput::CEvent Event)
 				aBuf[i] = *pSrc;
 			aBuf[i] = 0;
 
-			m_pCommand = m_pGameConsole->m_pConsole->GetCommandInfo(aBuf, m_CompletionFlagmask);
+			const IConsole::CCommandInfo *pCommand = m_pGameConsole->m_pConsole->GetCommandInfo(aBuf, m_CompletionFlagmask,
+				m_Type != CGameConsole::CONSOLETYPE_LOCAL && m_pGameConsole->Client()->RconAuthed() && m_pGameConsole->Client()->UseTempRconCommands());
+			if(pCommand)
+			{
+				m_IsCommand = true;
+				str_copy(m_aCommandName, pCommand->m_pName, IConsole::TEMPCMD_NAME_LENGTH);
+				str_copy(m_aCommandHelp, pCommand->m_pHelp, IConsole::TEMPCMD_HELP_LENGTH);
+				str_copy(m_aCommandParams, pCommand->m_pParams, IConsole::TEMPCMD_PARAMS_LENGTH);
+			}
+			else
+				m_IsCommand = false;
 		}
 	}
 }
@@ -449,19 +461,19 @@ void CGameConsole::OnRender()
 		{
 			if(pConsole->m_Input.GetString()[0] != 0)
 			{
-				m_pConsole->PossibleCommands(pConsole->m_aCompletionBuffer, pConsole->m_CompletionFlagmask, PossibleCommandsRenderCallback, &Info);
+				m_pConsole->PossibleCommands(pConsole->m_aCompletionBuffer, pConsole->m_CompletionFlagmask, m_ConsoleType != CGameConsole::CONSOLETYPE_LOCAL &&
+					Client()->RconAuthed() && Client()->UseTempRconCommands(), PossibleCommandsRenderCallback, &Info);
 				pConsole->m_CompletionRenderOffset = Info.m_Offset;
 
 				if(Info.m_EnumCount <= 0)
 				{
-					if(pConsole->m_pCommand)
+					if(pConsole->m_IsCommand)
 					{
-
 						char aBuf[512];
-						str_format(aBuf, sizeof(aBuf), "Help: %s ", pConsole->m_pCommand->m_pHelp);
+						str_format(aBuf, sizeof(aBuf), "Help: %s ", pConsole->m_aCommandHelp);
 						TextRender()->TextEx(&Info.m_Cursor, aBuf, -1);
 						TextRender()->TextColor(0.75f, 0.75f, 0.75f, 1);
-						str_format(aBuf, sizeof(aBuf), "Syntax: %s %s", pConsole->m_pCommand->m_pName, pConsole->m_pCommand->m_pParams);
+						str_format(aBuf, sizeof(aBuf), "Syntax: %s %s", pConsole->m_aCommandName, pConsole->m_aCommandParams);
 						TextRender()->TextEx(&Info.m_Cursor, aBuf, -1);
 					}
 				}
@@ -650,6 +662,16 @@ void CGameConsole::ClientConsolePrintCallback(const char *pStr, void *pUserData)
 	((CGameConsole *)pUserData)->m_LocalConsole.PrintLine(pStr);
 }
 
+void CGameConsole::ConchainConsoleOutputLevelUpdate(IConsole::IResult *pResult, void *pUserData, IConsole::FCommandCallback pfnCallback, void *pCallbackUserData)
+{
+	pfnCallback(pResult, pCallbackUserData);
+	if(pResult->NumArguments() == 1)
+	{
+		CGameConsole *pThis = static_cast<CGameConsole *>(pUserData);
+		pThis->Console()->SetPrintOutputLevel(pThis->m_PrintCBIndex, pResult->GetInteger(0));
+	}
+}
+
 void CGameConsole::PrintLine(int Type, const char *pLine)
 {
 	if(Type == CONSOLETYPE_LOCAL)
@@ -667,7 +689,7 @@ void CGameConsole::OnConsoleInit()
 	m_pConsole = Kernel()->RequestInterface<IConsole>();
 
 	//
-	Console()->RegisterPrintCallback(ClientConsolePrintCallback, this);
+	m_PrintCBIndex = Console()->RegisterPrintCallback(g_Config.m_ConsoleOutputLevel, ClientConsolePrintCallback, this);
 
 	Console()->Register("toggle_local_console", "", CFGFLAG_CLIENT, ConToggleLocalConsole, this, "Toggle local console");
 	Console()->Register("toggle_remote_console", "", CFGFLAG_CLIENT, ConToggleRemoteConsole, this, "Toggle remote console");
@@ -675,6 +697,8 @@ void CGameConsole::OnConsoleInit()
 	Console()->Register("clear_remote_console", "", CFGFLAG_CLIENT, ConClearRemoteConsole, this, "Clear remote console");
 	Console()->Register("dump_local_console", "", CFGFLAG_CLIENT, ConDumpLocalConsole, this, "Dump local console");
 	Console()->Register("dump_remote_console", "", CFGFLAG_CLIENT, ConDumpRemoteConsole, this, "Dump remote console");
+
+	Console()->Chain("console_output_level", ConchainConsoleOutputLevelUpdate, this);
 }
 
 void CGameConsole::OnStateChange(int NewState, int OldState)
diff --git a/src/game/client/components/console.h b/src/game/client/components/console.h
index 003a9423..6bcc75a6 100644
--- a/src/game/client/components/console.h
+++ b/src/game/client/components/console.h
@@ -33,7 +33,10 @@ class CGameConsole : public CComponent
 		int m_CompletionFlagmask;
 		float m_CompletionRenderOffset;
 
-		IConsole::CCommandInfo *m_pCommand;
+		bool m_IsCommand;
+		char m_aCommandName[IConsole::TEMPCMD_NAME_LENGTH];
+		char m_aCommandHelp[IConsole::TEMPCMD_HELP_LENGTH];
+		char m_aCommandParams[IConsole::TEMPCMD_PARAMS_LENGTH];
 
 		CInstance(int t);
 		void Init(CGameConsole *pGameConsole);
@@ -57,6 +60,7 @@ class CGameConsole : public CComponent
 
 	CInstance *CurrentConsole();
 	float TimeNow();
+	int m_PrintCBIndex;
 
 	int m_ConsoleType;
 	int m_ConsoleState;
@@ -74,6 +78,7 @@ class CGameConsole : public CComponent
 	static void ConClearRemoteConsole(IConsole::IResult *pResult, void *pUserData);
 	static void ConDumpLocalConsole(IConsole::IResult *pResult, void *pUserData);
 	static void ConDumpRemoteConsole(IConsole::IResult *pResult, void *pUserData);
+	static void ConchainConsoleOutputLevelUpdate(IConsole::IResult *pResult, void *pUserData, IConsole::FCommandCallback pfnCallback, void *pCallbackUserData);
 
 public:
 	enum
diff --git a/src/game/client/components/countryflags.cpp b/src/game/client/components/countryflags.cpp
index d6b30fe0..ef350cd7 100644
--- a/src/game/client/components/countryflags.cpp
+++ b/src/game/client/components/countryflags.cpp
@@ -69,6 +69,7 @@ void CCountryFlags::LoadCountryflagsIndexfile()
 		// add entry
 		CCountryFlag CountryFlag;
 		CountryFlag.m_CountryCode = CountryCode;
+		str_copy(CountryFlag.m_aCountryCodeString, aOrigin, sizeof(CountryFlag.m_aCountryCodeString));
 		CountryFlag.m_Texture = Graphics()->LoadTextureRaw(Info.m_Width, Info.m_Height, Info.m_Format, Info.m_pData, Info.m_Format, 0);
 		mem_free(Info.m_pData);
 		str_format(aBuf, sizeof(aBuf), "loaded country flag '%s'", aOrigin);
diff --git a/src/game/client/components/countryflags.h b/src/game/client/components/countryflags.h
index 15eb8598..ad24a762 100644
--- a/src/game/client/components/countryflags.h
+++ b/src/game/client/components/countryflags.h
@@ -12,9 +12,10 @@ public:
 	struct CCountryFlag
 	{
 		int m_CountryCode;
+		char m_aCountryCodeString[8];
 		int m_Texture;
 
-		bool operator<(const CCountryFlag &Other) { return m_CountryCode < Other.m_CountryCode; }
+		bool operator<(const CCountryFlag &Other) { return str_comp(m_aCountryCodeString, Other.m_aCountryCodeString) < 0; }
 	};
 
 	void OnInit();
diff --git a/src/game/client/components/emoticon.cpp b/src/game/client/components/emoticon.cpp
index 741a604f..b2f48b80 100644
--- a/src/game/client/components/emoticon.cpp
+++ b/src/game/client/components/emoticon.cpp
@@ -54,6 +54,7 @@ bool CEmoticon::OnMouseMove(float x, float y)
 	if(!m_Active)
 		return false;
 
+	UI()->ConvertMouseMove(&x, &y);
 	m_SelectorMouse += vec2(x,y);
 	return true;
 }
@@ -101,6 +102,13 @@ void CEmoticon::OnRender()
 		return;
 	}
 
+	if(m_pClient->m_Snap.m_SpecInfo.m_Active)
+	{
+		m_Active = false;
+		m_WasActive = false;
+		return;
+	}
+
 	m_WasActive = true;
 
 	if (length(m_SelectorMouse) > 140)
diff --git a/src/game/client/components/hud.cpp b/src/game/client/components/hud.cpp
index 58fc75b9..11343912 100644
--- a/src/game/client/components/hud.cpp
+++ b/src/game/client/components/hud.cpp
@@ -108,7 +108,9 @@ void CHud::RenderScoreHud()
 
 				if(GameFlags&GAMEFLAG_FLAGS)
 				{
-					if(FlagCarrier[t] == FLAG_ATSTAND || (FlagCarrier[t] == FLAG_TAKEN && ((Client()->GameTick()/10)&1)))
+					int BlinkTimer = (m_pClient->m_FlagDropTick[t] != 0 && 
+										(Client()->GameTick()-m_pClient->m_FlagDropTick[t])/Client()->GameTickSpeed() >= 25) ? 10 : 20;
+					if(FlagCarrier[t] == FLAG_ATSTAND || (FlagCarrier[t] == FLAG_TAKEN && ((Client()->GameTick()/BlinkTimer)&1)))
 					{
 						// draw flag
 						Graphics()->BlendNormal();
diff --git a/src/game/client/components/maplayers.cpp b/src/game/client/components/maplayers.cpp
index b9a2af16..096f9cc5 100644
--- a/src/game/client/components/maplayers.cpp
+++ b/src/game/client/components/maplayers.cpp
@@ -190,9 +190,11 @@ void CMapLayers::OnRender()
 					CTile *pTiles = (CTile *)m_pLayers->Map()->GetData(pTMap->m_Data);
 					Graphics()->BlendNone();
 					vec4 Color = vec4(pTMap->m_Color.r/255.0f, pTMap->m_Color.g/255.0f, pTMap->m_Color.b/255.0f, pTMap->m_Color.a/255.0f);
-					RenderTools()->RenderTilemap(pTiles, pTMap->m_Width, pTMap->m_Height, 32.0f, Color, TILERENDERFLAG_EXTEND|LAYERRENDERFLAG_OPAQUE);
+					RenderTools()->RenderTilemap(pTiles, pTMap->m_Width, pTMap->m_Height, 32.0f, Color, TILERENDERFLAG_EXTEND|LAYERRENDERFLAG_OPAQUE,
+													EnvelopeEval, this, pTMap->m_ColorEnv, pTMap->m_ColorEnvOffset);
 					Graphics()->BlendNormal();
-					RenderTools()->RenderTilemap(pTiles, pTMap->m_Width, pTMap->m_Height, 32.0f, Color, TILERENDERFLAG_EXTEND|LAYERRENDERFLAG_TRANSPARENT);
+					RenderTools()->RenderTilemap(pTiles, pTMap->m_Width, pTMap->m_Height, 32.0f, Color, TILERENDERFLAG_EXTEND|LAYERRENDERFLAG_TRANSPARENT,
+													EnvelopeEval, this, pTMap->m_ColorEnv, pTMap->m_ColorEnvOffset);
 				}
 				else if(pLayer->m_Type == LAYERTYPE_QUADS)
 				{
diff --git a/src/game/client/components/menus.cpp b/src/game/client/components/menus.cpp
index 9826d863..8f330f78 100644
--- a/src/game/client/components/menus.cpp
+++ b/src/game/client/components/menus.cpp
@@ -1125,7 +1125,9 @@ int CMenus::Render()
 				CListboxItem Item = UiDoListboxNextItem(&pEntry->m_CountryCode, OldSelected == i);
 				if(Item.m_Visible)
 				{
-					Item.m_Rect.Margin(10.0f, &Item.m_Rect);
+					CUIRect Label;
+					Item.m_Rect.Margin(5.0f, &Item.m_Rect);
+					Item.m_Rect.HSplitBottom(10.0f, &Item.m_Rect, &Label);
 					float OldWidth = Item.m_Rect.w;
 					Item.m_Rect.w = Item.m_Rect.h*2;
 					Item.m_Rect.x += (OldWidth-Item.m_Rect.w)/ 2.0f;
@@ -1135,6 +1137,7 @@ int CMenus::Render()
 					IGraphics::CQuadItem QuadItem(Item.m_Rect.x, Item.m_Rect.y, Item.m_Rect.w, Item.m_Rect.h);
 					Graphics()->QuadsDrawTL(&QuadItem, 1);
 					Graphics()->QuadsEnd();
+					UI()->DoLabel(&Label, pEntry->m_aCountryCodeString, 10.0f, 0);
 				}
 			}
 
@@ -1348,6 +1351,7 @@ bool CMenus::OnMouseMove(float x, float y)
 	if(!m_MenuActive)
 		return false;
 
+	UI()->ConvertMouseMove(&x, &y);
 	m_MousePos.x += x;
 	m_MousePos.y += y;
 	if(m_MousePos.x < 0) m_MousePos.x = 0;
diff --git a/src/game/client/components/menus_browser.cpp b/src/game/client/components/menus_browser.cpp
index f2926f87..8501c67d 100644
--- a/src/game/client/components/menus_browser.cpp
+++ b/src/game/client/components/menus_browser.cpp
@@ -252,7 +252,8 @@ void CMenus::RenderServerbrowserServerList(CUIRect View)
 							(!m_lFriends[f].m_pFriendInfo->m_aName[0] || NameHash == m_lFriends[f].m_pFriendInfo->m_NameHash))
 						{
 							m_lFriends[f].m_NumFound++;
-							break;
+							if(m_lFriends[f].m_pFriendInfo->m_aName[0])
+								break;
 						}
 					}
 				}
diff --git a/src/game/client/components/menus_settings.cpp b/src/game/client/components/menus_settings.cpp
index 3fb0ab94..51fdbd29 100644
--- a/src/game/client/components/menus_settings.cpp
+++ b/src/game/client/components/menus_settings.cpp
@@ -215,7 +215,9 @@ void CMenus::RenderSettingsPlayer(CUIRect MainView)
 		CListboxItem Item = UiDoListboxNextItem(&pEntry->m_CountryCode, OldSelected == i);
 		if(Item.m_Visible)
 		{
-			Item.m_Rect.Margin(10.0f, &Item.m_Rect);
+			CUIRect Label;
+			Item.m_Rect.Margin(5.0f, &Item.m_Rect);
+			Item.m_Rect.HSplitBottom(10.0f, &Item.m_Rect, &Label);
 			float OldWidth = Item.m_Rect.w;
 			Item.m_Rect.w = Item.m_Rect.h*2;
 			Item.m_Rect.x += (OldWidth-Item.m_Rect.w)/ 2.0f;
@@ -225,6 +227,7 @@ void CMenus::RenderSettingsPlayer(CUIRect MainView)
 			IGraphics::CQuadItem QuadItem(Item.m_Rect.x, Item.m_Rect.y, Item.m_Rect.w, Item.m_Rect.h);
 			Graphics()->QuadsDrawTL(&QuadItem, 1);
 			Graphics()->QuadsEnd();
+			UI()->DoLabel(&Label, pEntry->m_aCountryCodeString, 10.0f, 0);
 		}
 	}
 
@@ -812,10 +815,11 @@ class CLanguage
 {
 public:
 	CLanguage() {}
-	CLanguage(const char *n, const char *f) : m_Name(n), m_FileName(f) {}
+	CLanguage(const char *n, const char *f, int Code) : m_Name(n), m_FileName(f), m_CountryCode(Code) {}
 
 	string m_Name;
 	string m_FileName;
+	int m_CountryCode;
 
 	bool operator<(const CLanguage &Other) { return m_Name < Other.m_Name; }
 };
@@ -830,6 +834,7 @@ void LoadLanguageIndexfile(IStorage *pStorage, IConsole *pConsole, sorted_array<
 	}
 
 	char aOrigin[128];
+	char aReplacement[128];
 	CLineReader LineReader;
 	LineReader.Init(File);
 	char *pLine;
@@ -839,14 +844,32 @@ void LoadLanguageIndexfile(IStorage *pStorage, IConsole *pConsole, sorted_array<
 			continue;
 
 		str_copy(aOrigin, pLine, sizeof(aOrigin));
-		char *pReplacement = LineReader.Get();
-		if(!pReplacement)
+
+		pLine = LineReader.Get();
+		if(!pLine)
+		{
+			pConsole->Print(IConsole::OUTPUT_LEVEL_ADDINFO, "localization", "unexpected end of index file");
+			break;
+		}
+
+		if(pLine[0] != '=' || pLine[1] != '=' || pLine[2] != ' ')
+		{
+			char aBuf[128];
+			str_format(aBuf, sizeof(aBuf), "malform replacement for index '%s'", aOrigin);
+			pConsole->Print(IConsole::OUTPUT_LEVEL_ADDINFO, "localization", aBuf);
+			(void)LineReader.Get();
+			continue;
+		}
+		str_copy(aReplacement, pLine+3, sizeof(aReplacement));
+
+		pLine = LineReader.Get();
+		if(!pLine)
 		{
 			pConsole->Print(IConsole::OUTPUT_LEVEL_ADDINFO, "localization", "unexpected end of index file");
 			break;
 		}
 
-		if(pReplacement[0] != '=' || pReplacement[1] != '=' || pReplacement[2] != ' ')
+		if(pLine[0] != '=' || pLine[1] != '=' || pLine[2] != ' ')
 		{
 			char aBuf[128];
 			str_format(aBuf, sizeof(aBuf), "malform replacement for index '%s'", aOrigin);
@@ -856,7 +879,7 @@ void LoadLanguageIndexfile(IStorage *pStorage, IConsole *pConsole, sorted_array<
 
 		char aFileName[128];
 		str_format(aFileName, sizeof(aFileName), "languages/%s.txt", aOrigin);
-		pLanguages->add(CLanguage(pReplacement+3, aFileName));
+		pLanguages->add(CLanguage(aReplacement, aFileName, str_toint(pLine+3)));
 	}
 	io_close(File);
 }
@@ -870,7 +893,7 @@ void CMenus::RenderLanguageSelection(CUIRect MainView)
 
 	if(s_Languages.size() == 0)
 	{
-		s_Languages.add(CLanguage("English", ""));
+		s_Languages.add(CLanguage("English", "", 826));
 		LoadLanguageIndexfile(Storage(), Console(), &s_Languages);
 		for(int i = 0; i < s_Languages.size(); i++)
 			if(str_comp(s_Languages[i].m_FileName, g_Config.m_ClLanguagefile) == 0)
@@ -889,7 +912,19 @@ void CMenus::RenderLanguageSelection(CUIRect MainView)
 		CListboxItem Item = UiDoListboxNextItem(&r.front());
 
 		if(Item.m_Visible)
-			UI()->DoLabelScaled(&Item.m_Rect, r.front().m_Name, 16.0f, -1);
+		{
+			CUIRect Rect;
+			Item.m_Rect.VSplitLeft(Item.m_Rect.h*2.0f, &Rect, &Item.m_Rect);
+			Rect.VMargin(6.0f, &Rect);
+			Rect.HMargin(3.0f, &Rect);
+			Graphics()->TextureSet(m_pClient->m_pCountryFlags->GetByCountryCode(r.front().m_CountryCode)->m_Texture);
+			Graphics()->QuadsBegin();
+			IGraphics::CQuadItem QuadItem(Rect.x, Rect.y, Rect.w, Rect.h);
+			Graphics()->QuadsDrawTL(&QuadItem, 1);
+			Graphics()->QuadsEnd();
+			Item.m_Rect.HSplitTop(2.0f, 0, &Item.m_Rect);
+ 			UI()->DoLabelScaled(&Item.m_Rect, r.front().m_Name, 16.0f, -1);
+		}
 	}
 
 	s_SelectedLanguage = UiDoListboxEnd(&s_ScrollValue, 0);
diff --git a/src/game/client/components/spectator.cpp b/src/game/client/components/spectator.cpp
index e98df118..c09b2ee2 100644
--- a/src/game/client/components/spectator.cpp
+++ b/src/game/client/components/spectator.cpp
@@ -139,6 +139,7 @@ bool CSpectator::OnMouseMove(float x, float y)
 	if(!m_Active)
 		return false;
 
+	UI()->ConvertMouseMove(&x, &y);
 	m_SelectorMouse += vec2(x,y);
 	return true;
 }
@@ -161,6 +162,13 @@ void CSpectator::OnRender()
 		return;
 	}
 
+	if(!m_pClient->m_Snap.m_SpecInfo.m_Active)
+	{
+		m_Active = false;
+		m_WasActive = false;
+		return;
+	}
+
 	m_WasActive = true;
 	m_SelectedSpectatorID = NO_SELECTION;
 
diff --git a/src/game/client/gameclient.cpp b/src/game/client/gameclient.cpp
index a3c2dfc2..7b6b1192 100644
--- a/src/game/client/gameclient.cpp
+++ b/src/game/client/gameclient.cpp
@@ -341,6 +341,9 @@ void CGameClient::OnReset()
 		m_All.m_paComponents[i]->OnReset();
 
 	m_DemoSpecID = SPEC_FREEVIEW;
+	m_FlagDropTick[TEAM_RED] = 0;
+	m_FlagDropTick[TEAM_BLUE] = 0;
+	m_Tuning = CTuningParams();
 }
 
 
@@ -783,6 +786,20 @@ void CGameClient::OnNewSnapshot()
 			{
 				m_Snap.m_pGameDataObj = (const CNetObj_GameData *)pData;
 				m_Snap.m_GameDataSnapID = Item.m_ID;
+				if(m_Snap.m_pGameDataObj->m_FlagCarrierRed == FLAG_TAKEN)
+				{
+					if(m_FlagDropTick[TEAM_RED] == 0)
+						m_FlagDropTick[TEAM_RED] = Client()->GameTick();
+				}
+				else if(m_FlagDropTick[TEAM_RED] != 0)
+						m_FlagDropTick[TEAM_RED] = 0;
+				if(m_Snap.m_pGameDataObj->m_FlagCarrierBlue == FLAG_TAKEN)
+				{
+					if(m_FlagDropTick[TEAM_BLUE] == 0)
+						m_FlagDropTick[TEAM_BLUE] = Client()->GameTick();
+				}
+				else if(m_FlagDropTick[TEAM_BLUE] != 0)
+						m_FlagDropTick[TEAM_BLUE] = 0;
 			}
 			else if(Item.m_Type == NETOBJTYPE_FLAG)
 				m_Snap.m_paFlags[Item.m_ID%2] = (const CNetObj_Flag *)pData;
diff --git a/src/game/client/gameclient.h b/src/game/client/gameclient.h
index 859e1e7b..4783f8b4 100644
--- a/src/game/client/gameclient.h
+++ b/src/game/client/gameclient.h
@@ -89,6 +89,7 @@ public:
 	bool m_SuppressEvents;
 	bool m_NewTick;
 	bool m_NewPredictedTick;
+	int m_FlagDropTick[2];
 
 	// TODO: move this
 	CTuningParams m_Tuning;
diff --git a/src/game/client/lineinput.cpp b/src/game/client/lineinput.cpp
index 29b891c2..2de85d66 100644
--- a/src/game/client/lineinput.cpp
+++ b/src/game/client/lineinput.cpp
@@ -42,7 +42,7 @@ bool CLineInput::Manipulate(IInput::CEvent e, char *pStr, int StrMaxSize, int *p
 
 		if (Len < StrMaxSize - CharSize && CursorPos < StrMaxSize - CharSize)
 		{
-			mem_move(pStr + CursorPos + CharSize, pStr + CursorPos, Len - CursorPos + CharSize);
+			mem_move(pStr + CursorPos + CharSize, pStr + CursorPos, Len-CursorPos+1); // +1 == null term
 			for(int i = 0; i < CharSize; i++)
 				pStr[CursorPos+i] = Tmp[i];
 			CursorPos += CharSize;
diff --git a/src/game/client/render.h b/src/game/client/render.h
index dc7207be..d3d7fc40 100644
--- a/src/game/client/render.h
+++ b/src/game/client/render.h
@@ -39,6 +39,7 @@ enum
 	TILERENDERFLAG_EXTEND=4,
 };
 
+typedef void (*ENVELOPE_EVAL)(float TimeOffset, int Env, float *pChannels, void *pUser);
 
 class CRenderTools
 {
@@ -70,8 +71,8 @@ public:
 
 	// map render methods (gc_render_map.cpp)
 	static void RenderEvalEnvelope(CEnvPoint *pPoints, int NumPoints, int Channels, float Time, float *pResult);
-	void RenderQuads(CQuad *pQuads, int NumQuads, int Flags, void (*pfnEval)(float TimeOffset, int Env, float *pChannels, void *pUser), void *pUser);
-	void RenderTilemap(CTile *pTiles, int w, int h, float Scale, vec4 Color, int Flags);
+	void RenderQuads(CQuad *pQuads, int NumQuads, int Flags, ENVELOPE_EVAL pfnEval, void *pUser);
+	void RenderTilemap(CTile *pTiles, int w, int h, float Scale, vec4 Color, int RenderFlags, ENVELOPE_EVAL pfnEval, void *pUser, int ColorEnv, int ColorEnvOffset);
 
 	// helpers
 	void MapscreenToWorld(float CenterX, float CenterY, float ParallaxX, float ParallaxY,
diff --git a/src/game/client/render_map.cpp b/src/game/client/render_map.cpp
index 33cc1c7d..23fa42e0 100644
--- a/src/game/client/render_map.cpp
+++ b/src/game/client/render_map.cpp
@@ -78,7 +78,7 @@ static void Rotate(CPoint *pCenter, CPoint *pPoint, float Rotation)
 	pPoint->y = (int)(x * sinf(Rotation) + y * cosf(Rotation) + pCenter->y);
 }
 
-void CRenderTools::RenderQuads(CQuad *pQuads, int NumQuads, int RenderFlags, void (*pfnEval)(float TimeOffset, int Env, float *pChannels, void *pUser), void *pUser)
+void CRenderTools::RenderQuads(CQuad *pQuads, int NumQuads, int RenderFlags, ENVELOPE_EVAL pfnEval, void *pUser)
 {
 	Graphics()->QuadsBegin();
 	float Conv = 1/255.0f;
@@ -162,7 +162,8 @@ void CRenderTools::RenderQuads(CQuad *pQuads, int NumQuads, int RenderFlags, voi
 	Graphics()->QuadsEnd();
 }
 
-void CRenderTools::RenderTilemap(CTile *pTiles, int w, int h, float Scale, vec4 Color, int RenderFlags)
+void CRenderTools::RenderTilemap(CTile *pTiles, int w, int h, float Scale, vec4 Color, int RenderFlags,
+									ENVELOPE_EVAL pfnEval, void *pUser, int ColorEnv, int ColorEnvOffset)
 {
 	//Graphics()->TextureSet(img_get(tmap->image));
 	float ScreenX0, ScreenY0, ScreenX1, ScreenY1;
@@ -174,8 +175,19 @@ void CRenderTools::RenderTilemap(CTile *pTiles, int w, int h, float Scale, vec4
 	float FinalTileSize = Scale/(ScreenX1-ScreenX0) * Graphics()->ScreenWidth();
 	float FinalTilesetScale = FinalTileSize/TilePixelSize;
 
+	float r=1, g=1, b=1, a=1;
+	if(ColorEnv >= 0)
+	{
+		float aChannels[4];
+		pfnEval(ColorEnvOffset/1000.0f, ColorEnv, aChannels, pUser);
+		r = aChannels[0];
+		g = aChannels[1];
+		b = aChannels[2];
+		a = aChannels[3];
+	}
+
 	Graphics()->QuadsBegin();
-	Graphics()->SetColor(Color.r, Color.g, Color.b, Color.a);
+	Graphics()->SetColor(Color.r*r, Color.g*g, Color.b*b, Color.a*a);
 
 	int StartY = (int)(ScreenY0/Scale)-1;
 	int StartX = (int)(ScreenX0/Scale)-1;
diff --git a/src/game/client/ui.cpp b/src/game/client/ui.cpp
index 2161bc77..00a30c15 100644
--- a/src/game/client/ui.cpp
+++ b/src/game/client/ui.cpp
@@ -53,6 +53,13 @@ int CUI::MouseInside(const CUIRect *r)
 	return 0;
 }
 
+void CUI::ConvertMouseMove(float *x, float *y)
+{
+	float Fac = (float)(g_Config.m_UiMousesens)/g_Config.m_InpMousesens;
+	*x = *x*Fac;
+	*y = *y*Fac;
+}
+
 CUIRect *CUI::Screen()
 {
 	float Aspect = Graphics()->ScreenAspect();
diff --git a/src/game/client/ui.h b/src/game/client/ui.h
index 017abf7c..7cd78d6f 100644
--- a/src/game/client/ui.h
+++ b/src/game/client/ui.h
@@ -79,6 +79,7 @@ public:
 	const void *LastActiveItem() const { return m_pLastActiveItem; }
 
 	int MouseInside(const CUIRect *pRect);
+	void ConvertMouseMove(float *x, float *y);
 
 	CUIRect *Screen();
 	void ClipEnable(const CUIRect *pRect);
diff --git a/src/game/editor/auto_map.cpp b/src/game/editor/auto_map.cpp
new file mode 100644
index 00000000..528e459b
--- /dev/null
+++ b/src/game/editor/auto_map.cpp
@@ -0,0 +1,202 @@
+#include <stdio.h>	// sscanf
+
+#include <engine/console.h>
+#include <engine/storage.h>
+#include <engine/shared/linereader.h>
+
+#include "auto_map.h"
+#include "editor.h"
+
+CAutoMapper::CAutoMapper(CEditor *pEditor)
+{
+	m_pEditor = pEditor;
+	m_FileLoaded = false;
+}
+
+void CAutoMapper::Load(const char* pTileName)
+{
+	char aPath[256];
+	str_format(aPath, sizeof(aPath), "editor/%s.rules", pTileName);
+	IOHANDLE RulesFile = m_pEditor->Storage()->OpenFile(aPath, IOFLAG_READ, IStorage::TYPE_ALL);
+	if(!RulesFile)
+		return;
+	
+	CLineReader LineReader;
+	LineReader.Init(RulesFile);
+		
+	CConfiguration *pCurrentConf = 0;
+	CIndexRule *pCurrentIndex = 0;
+		
+	char aBuf[256];
+		
+	// read each line
+	while(char *pLine = LineReader.Get())
+	{
+		// skip blank/empty lines as well as comments
+		if(str_length(pLine) > 0 && pLine[0] != '#' && pLine[0] != '\n' && pLine[0] != '\r'
+			&& pLine[0] != '\t' && pLine[0] != '\v' && pLine[0] != ' ')
+		{
+			if(pLine[0]== '[')
+			{
+				// new configuration, get the name
+				pLine++;
+					
+				CConfiguration NewConf;
+				int ID = m_lConfigs.add(NewConf);
+				pCurrentConf = &m_lConfigs[ID];
+					
+				str_copy(pCurrentConf->m_aName, pLine, str_length(pLine));
+			}
+			else
+			{
+				if(!str_comp_num(pLine, "Index", 5))
+				{
+					// new index
+					int ID = 0;
+					char aFlip[128] = "";
+						
+					sscanf(pLine, "Index %d %127s", &ID, aFlip);
+						
+					CIndexRule NewIndexRule;
+					NewIndexRule.m_ID = ID;
+					NewIndexRule.m_Flag = 0;
+					NewIndexRule.m_RandomValue = 0;
+					NewIndexRule.m_BaseTile = false;
+						
+					if(str_length(aFlip) > 0)
+					{
+						if(!str_comp(aFlip, "XFLIP"))
+							NewIndexRule.m_Flag = TILEFLAG_VFLIP;
+						else if(!str_comp(aFlip, "YFLIP"))
+							NewIndexRule.m_Flag = TILEFLAG_HFLIP;
+					}
+						
+					// add the index rule object and make it current
+					int ArrayID = pCurrentConf->m_aIndexRules.add(NewIndexRule);
+					pCurrentIndex = &pCurrentConf->m_aIndexRules[ArrayID];
+				}
+				else if(!str_comp_num(pLine, "BaseTile", 8) && pCurrentIndex)
+				{
+					pCurrentIndex->m_BaseTile = true;
+				}
+				else if(!str_comp_num(pLine, "Pos", 3) && pCurrentIndex)
+				{
+					int x = 0, y = 0;
+					char aValue[128];
+					int Value = CPosRule::EMPTY;
+					bool IndexValue = false;
+						
+					sscanf(pLine, "Pos %d %d %127s", &x, &y, aValue);
+						
+					if(!str_comp(aValue, "FULL"))
+						Value = CPosRule::FULL;
+					else if(!str_comp_num(aValue, "INDEX", 5))
+					{
+						sscanf(pLine, "Pos %*d %*d INDEX %d", &Value);
+						IndexValue = true;
+					}
+
+					CPosRule NewPosRule = {x, y, Value, IndexValue};
+					pCurrentIndex->m_aRules.add(NewPosRule);
+				}
+				else if(!str_comp_num(pLine, "Random", 6) && pCurrentIndex)
+				{
+					sscanf(pLine, "Random %d", &pCurrentIndex->m_RandomValue);
+				}
+			}
+		}
+	}
+		
+	io_close(RulesFile);
+		
+	str_format(aBuf, sizeof(aBuf),"loaded %s", aPath);
+	m_pEditor->Console()->Print(IConsole::OUTPUT_LEVEL_DEBUG, "editor", aBuf);
+		
+	m_FileLoaded = true;
+}
+
+const char* CAutoMapper::GetConfigName(int Index)
+{
+	if(Index < 0 || Index >= m_lConfigs.size())
+		return "";
+
+	return m_lConfigs[Index].m_aName;
+}
+
+void CAutoMapper::Proceed(CLayerTiles *pLayer, int ConfigID)
+{
+	if(!m_FileLoaded || pLayer->m_Readonly || ConfigID < 0 || ConfigID >= m_lConfigs.size())
+		return;
+	
+	CConfiguration *pConf = &m_lConfigs[ConfigID];
+	
+	if(!pConf->m_aIndexRules.size())
+		return;
+	
+	int BaseTile = 1;
+	
+	// find base tile if there is one
+	for(int i = 0; i < pConf->m_aIndexRules.size(); ++i)
+	{
+		if(pConf->m_aIndexRules[i].m_BaseTile)
+		{
+			BaseTile = pConf->m_aIndexRules[i].m_ID;
+			break;
+		}
+	}
+	
+	// auto map !
+	int MaxIndex = pLayer->m_Width*pLayer->m_Height;
+	for(int y = 0; y < pLayer->m_Height; y++)
+		for(int x = 0; x < pLayer->m_Width; x++)
+		{
+			CTile *pTile = &(pLayer->m_pTiles[y*pLayer->m_Width+x]);
+			if(pTile->m_Index == 0)
+				continue;
+
+			pTile->m_Index = BaseTile;
+			m_pEditor->m_Map.m_Modified = true;
+
+			if(y == 0 || y == pLayer->m_Height-1 || x == 0 || x == pLayer->m_Width-1)
+				continue;
+				
+			for(int i = 0; i < pConf->m_aIndexRules.size(); ++i)
+			{
+				if(pConf->m_aIndexRules[i].m_BaseTile)
+					continue;
+
+				bool RespectRules = true;
+				for(int j = 0; j < pConf->m_aIndexRules[i].m_aRules.size() && RespectRules; ++j)
+				{
+					CPosRule *pRule = &pConf->m_aIndexRules[i].m_aRules[j];
+					int CheckIndex = (y+pRule->m_Y)*pLayer->m_Width+(x+pRule->m_X);
+							
+					if(CheckIndex < 0 || CheckIndex >= MaxIndex)
+						RespectRules = false;
+					else
+					{
+ 						if(pRule->m_IndexValue)
+						{
+							if(pLayer->m_pTiles[CheckIndex].m_Index != pRule->m_Value)
+								RespectRules = false;
+						}
+						else
+						{
+							if(pLayer->m_pTiles[CheckIndex].m_Index > 0 && pRule->m_Value == CPosRule::EMPTY)
+								RespectRules = false;
+									
+							if(pLayer->m_pTiles[CheckIndex].m_Index == 0 && pRule->m_Value == CPosRule::FULL)
+								RespectRules = false;
+						}
+					}
+				}
+					
+				if(RespectRules &&
+					(pConf->m_aIndexRules[i].m_RandomValue <= 1 || (int)((float)rand() / ((float)RAND_MAX + 1) * pConf->m_aIndexRules[i].m_RandomValue)  == 1))
+				{
+					pTile->m_Index = pConf->m_aIndexRules[i].m_ID;
+					pTile->m_Flags = pConf->m_aIndexRules[i].m_Flag;
+				}
+			}
+		}
+}
diff --git a/src/game/editor/auto_map.h b/src/game/editor/auto_map.h
new file mode 100644
index 00000000..ee570378
--- /dev/null
+++ b/src/game/editor/auto_map.h
@@ -0,0 +1,54 @@
+#ifndef GAME_EDITOR_AUTO_MAP_H
+#define GAME_EDITOR_AUTO_MAP_H
+
+#include <base/tl/array.h>
+
+class CAutoMapper
+{
+	struct CPosRule
+	{
+		int m_X;
+		int m_Y;
+		int m_Value;
+		bool m_IndexValue;
+		
+		enum
+		{
+			EMPTY=0,
+			FULL
+		};
+	};
+
+	struct CIndexRule
+	{
+		int m_ID;
+		array<CPosRule> m_aRules;
+		int m_Flag;
+		int m_RandomValue;
+		bool m_BaseTile;
+	};
+
+	struct CConfiguration
+	{
+		array<CIndexRule> m_aIndexRules;
+		char m_aName[128];
+	};
+	
+public:
+	CAutoMapper(class CEditor *pEditor);
+	
+	void Load(const char* pTileName);
+	void Proceed(class CLayerTiles *pLayer, int ConfigID);
+
+	int ConfigNamesNum() { return m_lConfigs.size(); }
+	const char* GetConfigName(int Index);
+	
+	const bool IsLoaded() { return m_FileLoaded; }
+private:
+	array<CConfiguration> m_lConfigs;
+	class CEditor *m_pEditor;
+	bool m_FileLoaded;
+};
+
+
+#endif
diff --git a/src/game/editor/editor.cpp b/src/game/editor/editor.cpp
index 8c186085..500e600b 100644
--- a/src/game/editor/editor.cpp
+++ b/src/game/editor/editor.cpp
@@ -8,20 +8,20 @@
 #include <engine/client.h>
 #include <engine/console.h>
 #include <engine/graphics.h>
-#include <engine/textrender.h>
 #include <engine/input.h>
 #include <engine/keys.h>
 #include <engine/storage.h>
+#include <engine/textrender.h>
 
-#include <game/client/ui.h>
 #include <game/gamecore.h>
+#include <game/localization.h>
+#include <game/client/lineinput.h>
 #include <game/client/render.h>
+#include <game/client/ui.h>
 #include <game/generated/client_data.h>
 
+#include "auto_map.h"
 #include "editor.h"
-#include <game/client/lineinput.h>
-
-#include <game/localization.h>
 
 int CEditor::ms_CheckerTexture;
 int CEditor::ms_BackgroundTexture;
@@ -41,9 +41,10 @@ CEditorImage::~CEditorImage()
 
 CLayerGroup::CLayerGroup()
 {
-	m_pName = "";
+	m_aName[0] = 0;
 	m_Visible = true;
 	m_SaveToMap = true;
+	m_Collapse = false;
 	m_GameGroup = false;
 	m_OffsetX = 0;
 	m_OffsetY = 0;
@@ -189,6 +190,24 @@ void CEditorImage::AnalyseTileFlags()
 
 }
 
+void CEditor::EnvelopeEval(float TimeOffset, int Env, float *pChannels, void *pUser)
+{
+	CEditor *pThis = (CEditor *)pUser;
+	if(Env < 0 || Env >= pThis->m_Map.m_lEnvelopes.size())
+	{
+		pChannels[0] = 0;
+		pChannels[1] = 0;
+		pChannels[2] = 0;
+		pChannels[3] = 0;
+		return;
+	}
+
+	CEnvelope *e = pThis->m_Map.m_lEnvelopes[Env];
+	float t = pThis->m_AnimateTime+TimeOffset;
+	t *= pThis->m_AnimateSpeed;
+	e->Eval(t, pChannels);
+}
+
 /********************************************************
  OTHER
 *********************************************************/
@@ -196,32 +215,59 @@ void CEditorImage::AnalyseTileFlags()
 // copied from gc_menu.cpp, should be more generalized
 //extern int ui_do_edit_box(void *id, const CUIRect *rect, char *str, int str_size, float font_size, bool hidden=false);
 
-int CEditor::DoEditBox(void *pID, const CUIRect *pRect, char *pStr, unsigned StrSize, float FontSize, bool Hidden)
+int CEditor::DoEditBox(void *pID, const CUIRect *pRect, char *pStr, unsigned StrSize, float FontSize, float *Offset, bool Hidden, int Corners)
 {
-    int Inside = UI()->MouseInside(pRect);
+	int Inside = UI()->MouseInside(pRect);
 	bool ReturnValue = false;
+	bool UpdateOffset = false;
 	static int s_AtIndex = 0;
+	static bool s_DoScroll = false;
+	static float s_ScrollStart = 0.0f;
+
+	FontSize *= UI()->Scale();
 
 	if(UI()->LastActiveItem() == pID)
 	{
 		int Len = str_length(pStr);
+		if(Len == 0)
+			s_AtIndex = 0;
 
 		if(Inside && UI()->MouseButton(0))
 		{
+			s_DoScroll = true;
+			s_ScrollStart = UI()->MouseX();
 			int MxRel = (int)(UI()->MouseX() - pRect->x);
 
-			for (int i = 1; i <= Len; i++)
+			for(int i = 1; i <= Len; i++)
 			{
-				if (TextRender()->TextWidth(0, FontSize, pStr, i) + 10 > MxRel)
+				if(TextRender()->TextWidth(0, FontSize, pStr, i) - *Offset > MxRel)
 				{
 					s_AtIndex = i - 1;
 					break;
 				}
 
-				if (i == Len)
+				if(i == Len)
 					s_AtIndex = Len;
 			}
 		}
+		else if(!UI()->MouseButton(0))
+			s_DoScroll = false;
+		else if(s_DoScroll)
+		{
+			// do scrolling
+			if(UI()->MouseX() < pRect->x && s_ScrollStart-UI()->MouseX() > 10.0f)
+			{
+				s_AtIndex = max(0, s_AtIndex-1);
+				s_ScrollStart = UI()->MouseX();
+				UpdateOffset = true;
+			}
+			else if(UI()->MouseX() > pRect->x+pRect->w && UI()->MouseX()-s_ScrollStart > 10.0f)
+			{
+				s_AtIndex = min(Len, s_AtIndex+1);
+				s_ScrollStart = UI()->MouseX();
+				UpdateOffset = true;
+			}
+		}
 
 		for(int i = 0; i < Input()->NumEvents(); i++)
 		{
@@ -235,7 +281,11 @@ int CEditor::DoEditBox(void *pID, const CUIRect *pRect, char *pStr, unsigned Str
 	if(UI()->ActiveItem() == pID)
 	{
 		if(!UI()->MouseButton(0))
+		{
+			s_AtIndex = min(s_AtIndex, str_length(pStr));
+			s_DoScroll = false;
 			UI()->SetActiveItem(0);
+		}
 	}
 	else if(UI()->HotItem() == pID)
 	{
@@ -251,8 +301,8 @@ int CEditor::DoEditBox(void *pID, const CUIRect *pRect, char *pStr, unsigned Str
 		UI()->SetHotItem(pID);
 
 	CUIRect Textbox = *pRect;
-	RenderTools()->DrawUIRect(&Textbox, vec4(1,1,1,0.5f), CUI::CORNER_ALL, 3.0f);
-	Textbox.VMargin(3.0f, &Textbox);
+	RenderTools()->DrawUIRect(&Textbox, vec4(1, 1, 1, 0.5f), Corners, 3.0f);
+	Textbox.VMargin(2.0f, &Textbox);
 
 	const char *pDisplayStr = pStr;
 	char aStars[128];
@@ -268,19 +318,47 @@ int CEditor::DoEditBox(void *pID, const CUIRect *pRect, char *pStr, unsigned Str
 		pDisplayStr = aStars;
 	}
 
+	// check if the text has to be moved
+	if(UI()->LastActiveItem() == pID && !JustGotActive && (UpdateOffset || Input()->NumEvents()))
+	{
+		float w = TextRender()->TextWidth(0, FontSize, pDisplayStr, s_AtIndex);
+		if(w-*Offset > Textbox.w)
+		{
+			// move to the left
+			float wt = TextRender()->TextWidth(0, FontSize, pDisplayStr, -1);
+			do
+			{
+				*Offset += min(wt-*Offset-Textbox.w, Textbox.w/3);
+			}
+			while(w-*Offset > Textbox.w);
+		}
+		else if(w-*Offset < 0.0f)
+		{
+			// move to the right
+			do
+			{
+				*Offset = max(0.0f, *Offset-Textbox.w/3);
+			}
+			while(w-*Offset < 0.0f);
+		}
+	}
+	UI()->ClipEnable(pRect);
+	Textbox.x -= *Offset;
+
 	UI()->DoLabel(&Textbox, pDisplayStr, FontSize, -1);
-	
-	//TODO: make it blink
+
+	// render the cursor
 	if(UI()->LastActiveItem() == pID && !JustGotActive)
 	{
 		float w = TextRender()->TextWidth(0, FontSize, pDisplayStr, s_AtIndex);
 		Textbox = *pRect;
 		Textbox.VSplitLeft(2.0f, 0, &Textbox);
-		Textbox.x += w*UI()->Scale();
-		Textbox.y -= FontSize/10.f;
-		
-		UI()->DoLabel(&Textbox, "|", FontSize*1.1f, -1);
+		Textbox.x += (w-*Offset-TextRender()->TextWidth(0, FontSize, "|", -1)/2);
+
+		if((2*time_get()/time_freq()) % 2)	// make it blink
+			UI()->DoLabel(&Textbox, "|", FontSize, -1);
 	}
+	UI()->ClipDisable();
 
 	return ReturnValue;
 }
@@ -443,12 +521,12 @@ int CEditor::DoButton_Tab(const void *pID, const char *pText, int Checked, const
 	return DoButton_Editor_Common(pID, pText, Checked, pRect, Flags, pToolTip);
 }
 
-int CEditor::DoButton_Ex(const void *pID, const char *pText, int Checked, const CUIRect *pRect, int Flags, const char *pToolTip, int Corners)
+int CEditor::DoButton_Ex(const void *pID, const char *pText, int Checked, const CUIRect *pRect, int Flags, const char *pToolTip, int Corners, float FontSize)
 {
 	RenderTools()->DrawUIRect(pRect, GetButtonColor(pID, Checked), Corners, 3.0f);
     CUIRect NewRect = *pRect;
-    NewRect.y += NewRect.h/2.0f-7.0f;
-    UI()->DoLabel(&NewRect, pText, 10, 0, -1);
+    NewRect.HMargin(NewRect.h/2.0f-FontSize/2.0f-1.0f, &NewRect);
+    UI()->DoLabel(&NewRect, pText, FontSize, 0, -1);
 	return DoButton_Editor_Common(pID, pText, Checked, pRect, Flags, pToolTip);
 }
 
@@ -466,6 +544,49 @@ int CEditor::DoButton_ButtonDec(const void *pID, const char *pText, int Checked,
 	return DoButton_Editor_Common(pID, pText, Checked, pRect, Flags, pToolTip);
 }
 
+void CEditor::RenderGrid(CLayerGroup *pGroup)
+{
+	if(!m_GridActive)
+		return;
+
+	float aGroupPoints[4];
+	pGroup->Mapping(aGroupPoints); 
+
+	float w = UI()->Screen()->w;
+	float h = UI()->Screen()->h;
+
+	int LineDistance = GetLineDistance();
+
+	int XOffset = aGroupPoints[0]/LineDistance;
+	int YOffset = aGroupPoints[1]/LineDistance;
+	int XGridOffset = XOffset % m_GridFactor;
+	int YGridOffset = YOffset % m_GridFactor;
+
+	Graphics()->TextureSet(-1);	
+	Graphics()->LinesBegin();
+
+	for(int i = 0; i < (int)w; i++)
+	{
+		if((i+YGridOffset) % m_GridFactor == 0)
+			Graphics()->SetColor(1.0f, 0.3f, 0.3f, 0.3f);
+		else
+			Graphics()->SetColor(1.0f, 1.0f, 1.0f, 0.15f);
+
+		IGraphics::CLineItem Line = IGraphics::CLineItem(LineDistance*XOffset, LineDistance*i+LineDistance*YOffset, w+aGroupPoints[2], LineDistance*i+LineDistance*YOffset);
+		Graphics()->LinesDraw(&Line, 1);
+
+		if((i+XGridOffset) % m_GridFactor == 0)
+			Graphics()->SetColor(1.0f, 0.3f, 0.3f, 0.3f);
+		else
+			Graphics()->SetColor(1.0f, 1.0f, 1.0f, 0.15f);
+
+		Line = IGraphics::CLineItem(LineDistance*i+LineDistance*XOffset, LineDistance*YOffset, LineDistance*i+LineDistance*XOffset, h+aGroupPoints[3]);
+		Graphics()->LinesDraw(&Line, 1);
+	}
+	Graphics()->SetColor(1.0f, 1.0f, 1.0f, 1.0f);
+	Graphics()->LinesEnd();
+}
+
 void CEditor::RenderBackground(CUIRect View, int Texture, float Size, float Brightness)
 {
 	Graphics()->TextureSet(Texture);
@@ -738,13 +859,6 @@ void CEditor::DoToolbar(CUIRect ToolBar)
 			m_AnimateSpeed -= 0.5f;
 	}
 
-	if(Input()->KeyPresses(KEY_MOUSE_WHEEL_UP) && m_Dialog == DIALOG_NONE)
-		m_ZoomLevel -= 20;
-
-	if(Input()->KeyPresses(KEY_MOUSE_WHEEL_DOWN) && m_Dialog == DIALOG_NONE)
-		m_ZoomLevel += 20;
-
-	m_ZoomLevel = clamp(m_ZoomLevel, 50, 2000);
 	m_WorldZoom = m_ZoomLevel/100.0f;
 
 	TB_Top.VSplitLeft(10.0f, &Button, &TB_Top);
@@ -857,6 +971,41 @@ void CEditor::DoToolbar(CUIRect ToolBar)
 		m_WorldOffsetX = 0;
 		m_WorldOffsetY = 0;
 	}
+
+	TB_Bottom.VSplitLeft(5.0f, 0, &TB_Bottom);
+
+	// grid button
+	TB_Bottom.VSplitLeft(50.0f, &Button, &TB_Bottom);
+	static int s_GridButton = 0;
+	if(DoButton_Editor(&s_GridButton, "Grid", m_GridActive, &Button, 0, "Toggle Grid"))
+	{
+		m_GridActive = !m_GridActive;
+	}
+
+	TB_Bottom.VSplitLeft(30.0f, 0, &TB_Bottom);
+
+	// grid zoom
+	TB_Bottom.VSplitLeft(30.0f, &Button, &TB_Bottom);
+	static int s_GridIncreaseButton = 0;
+	if(DoButton_Ex(&s_GridIncreaseButton, "G-", 0, &Button, 0, "Decrease grid", CUI::CORNER_L))
+	{
+		if(m_GridFactor > 1)
+			m_GridFactor--;
+	}
+
+	TB_Bottom.VSplitLeft(30.0f, &Button, &TB_Bottom);
+	static int s_GridNormalButton = 0;
+	if(DoButton_Ex(&s_GridNormalButton, "1", 0, &Button, 0, "Normal grid", 0))
+		m_GridFactor = 1;
+
+	TB_Bottom.VSplitLeft(30.0f, &Button, &TB_Bottom);
+
+	static int s_GridDecreaseButton = 0;
+	if(DoButton_Ex(&s_GridDecreaseButton, "G+", 0, &Button, 0, "Increase grid", CUI::CORNER_R))
+	{
+		if(m_GridFactor < 15)
+			m_GridFactor++;
+	}
 }
 
 static void Rotate(CPoint *pCenter, CPoint *pPoint, float Rotation)
@@ -916,10 +1065,41 @@ void CEditor::DoQuad(CQuad *q, int Index)
 		else if(s_Operation == OP_MOVE_ALL)
 		{
 			// move all points including pivot
-			for(int v = 0; v < 5; v++)
+			if(m_GridActive)
 			{
-				q->m_aPoints[v].x += f2fx(wx-s_LastWx);
-				q->m_aPoints[v].y += f2fx(wy-s_LastWy);
+				int LineDistance = GetLineDistance();
+
+				float x = 0.0f;
+				float y = 0.0f;
+				if(wx >= 0)
+					x = (int)((wx+(LineDistance/2)*m_GridFactor)/(LineDistance*m_GridFactor)) * (LineDistance*m_GridFactor);
+				else
+					x = (int)((wx-(LineDistance/2)*m_GridFactor)/(LineDistance*m_GridFactor)) * (LineDistance*m_GridFactor);
+				if(wy >= 0)
+					y = (int)((wy+(LineDistance/2)*m_GridFactor)/(LineDistance*m_GridFactor)) * (LineDistance*m_GridFactor);
+				else
+					y = (int)((wy-(LineDistance/2)*m_GridFactor)/(LineDistance*m_GridFactor)) * (LineDistance*m_GridFactor);
+				
+				int OldX = q->m_aPoints[4].x;
+				int OldY = q->m_aPoints[4].y;
+				q->m_aPoints[4].x = f2fx(x);
+				q->m_aPoints[4].y = f2fx(y);
+				int DiffX = q->m_aPoints[4].x - OldX;
+				int DiffY = q->m_aPoints[4].y - OldY;
+				
+				for(int v = 0; v < 4; v++)
+				{
+					q->m_aPoints[v].x += DiffX;
+					q->m_aPoints[v].y += DiffY;
+				}
+			}
+			else
+			{
+				for(int v = 0; v < 5; v++)
+				{
+						q->m_aPoints[v].x += f2fx(wx-s_LastWx);
+						q->m_aPoints[v].y += f2fx(wy-s_LastWy);
+				}
 			}
 		}
 		else if(s_Operation == OP_ROTATE)
@@ -1050,12 +1230,37 @@ void CEditor::DoQuadPoint(CQuad *pQuad, int QuadIndex, int V)
 		{
 			if(s_Operation == OP_MOVEPOINT)
 			{
-				for(int m = 0; m < 4; m++)
-					if(m_SelectedPoints&(1<<m))
-					{
-						pQuad->m_aPoints[m].x += f2fx(dx);
-						pQuad->m_aPoints[m].y += f2fx(dy);
-					}
+				if(m_GridActive)
+				{
+					for(int m = 0; m < 4; m++)
+						if(m_SelectedPoints&(1<<m))
+						{
+							int LineDistance = GetLineDistance();
+
+							float x = 0.0f;
+							float y = 0.0f;
+							if(wx >= 0)
+								x = (int)((wx+(LineDistance/2)*m_GridFactor)/(LineDistance*m_GridFactor)) * (LineDistance*m_GridFactor);
+							else
+								x = (int)((wx-(LineDistance/2)*m_GridFactor)/(LineDistance*m_GridFactor)) * (LineDistance*m_GridFactor);
+							if(wy >= 0)
+								y = (int)((wy+(LineDistance/2)*m_GridFactor)/(LineDistance*m_GridFactor)) * (LineDistance*m_GridFactor);
+							else
+								y = (int)((wy-(LineDistance/2)*m_GridFactor)/(LineDistance*m_GridFactor)) * (LineDistance*m_GridFactor);
+
+							pQuad->m_aPoints[m].x = f2fx(x);
+							pQuad->m_aPoints[m].y = f2fx(y);
+						}
+				}
+				else
+				{
+					for(int m = 0; m < 4; m++)
+						if(m_SelectedPoints&(1<<m))
+						{
+							pQuad->m_aPoints[m].x += f2fx(dx);
+							pQuad->m_aPoints[m].y += f2fx(dy);
+						}
+				}
 			}
 			else if(s_Operation == OP_MOVEUV)
 			{
@@ -1248,6 +1453,8 @@ void CEditor::DoMapEditor(CUIRect View, CUIRect ToolBar)
 		{
 			g->MapScreen();
 
+			RenderGrid(g);
+
 			for(int i = 0; i < NumEditLayers; i++)
 			{
 				if(pEditLayers[i]->m_Type != LAYERTYPE_TILES)
@@ -1768,9 +1975,13 @@ void CEditor::RenderLayers(CUIRect ToolBox, CUIRect ToolBar, CUIRect View)
 	static float s_ScrollValue = 0;
 
 	for(int g = 0; g < m_Map.m_lGroups.size(); g++)
+	{
 		// Each group is 19.0f
 		// Each layer is 14.0f
-		LayersHeight += 19.0f + m_Map.m_lGroups[g]->m_lLayers.size() * 14.0f;
+		LayersHeight += 19.0f;
+		if(!m_Map.m_lGroups[g]->m_Collapse)
+			LayersHeight += m_Map.m_lGroups[g]->m_lLayers.size() * 14.0f;
+	}
 
 	float ScrollDifference = LayersHeight - LayersBox.h;
 
@@ -1781,6 +1992,20 @@ void CEditor::RenderLayers(CUIRect ToolBox, CUIRect ToolBar, CUIRect View)
 		LayersBox.VSplitRight(3.0f, &LayersBox, 0);	// extra spacing
 		Scroll.HMargin(5.0f, &Scroll);
 		s_ScrollValue = UiDoScrollbarV(&s_ScrollBar, &Scroll, s_ScrollValue);
+
+		if(UI()->MouseInside(&Scroll) || UI()->MouseInside(&LayersBox))
+		{
+			int ScrollNum = (int)((LayersHeight-LayersBox.h)/15.0f)+1;
+			if(ScrollNum > 0)
+			{
+				if(Input()->KeyPresses(KEY_MOUSE_WHEEL_UP))
+					s_ScrollValue = clamp(s_ScrollValue - 1.0f/ScrollNum, 0.0f, 1.0f);
+				if(Input()->KeyPresses(KEY_MOUSE_WHEEL_DOWN))
+					s_ScrollValue = clamp(s_ScrollValue + 1.0f/ScrollNum, 0.0f, 1.0f);
+			}
+			else
+				ScrollNum = 0;
+		}
 	}
 
 	float LayerStartAt = ScrollDifference * s_ScrollValue;
@@ -1807,7 +2032,7 @@ void CEditor::RenderLayers(CUIRect ToolBox, CUIRect ToolBar, CUIRect View)
 			{
 				LayersBox.HSplitTop(12.0f, &Slot, &LayersBox);
 				Slot.VSplitLeft(12, &VisibleToggle, &Slot);
-				if(DoButton_Ex(&m_Map.m_lGroups[g]->m_Visible, m_Map.m_lGroups[g]->m_Visible?"V":"H", 0, &VisibleToggle, 0, "Toggle group visibility", CUI::CORNER_L))
+				if(DoButton_Ex(&m_Map.m_lGroups[g]->m_Visible, m_Map.m_lGroups[g]->m_Visible?"V":"H", m_Map.m_lGroups[g]->m_Collapse ? 1 : 0, &VisibleToggle, 0, "Toggle group visibility", CUI::CORNER_L))
 					m_Map.m_lGroups[g]->m_Visible = !m_Map.m_lGroups[g]->m_Visible;
 
 				Slot.VSplitRight(12.0f, &Slot, &SaveCheck);
@@ -1815,16 +2040,22 @@ void CEditor::RenderLayers(CUIRect ToolBox, CUIRect ToolBar, CUIRect View)
 					if(!m_Map.m_lGroups[g]->m_GameGroup)
 						m_Map.m_lGroups[g]->m_SaveToMap = !m_Map.m_lGroups[g]->m_SaveToMap;
 
-				str_format(aBuf, sizeof(aBuf),"#%d %s", g, m_Map.m_lGroups[g]->m_pName);
+				str_format(aBuf, sizeof(aBuf),"#%d %s", g, m_Map.m_lGroups[g]->m_aName);
+				float FontSize = 10.0f;
+				while(TextRender()->TextWidth(0, FontSize, aBuf, -1) > Slot.w)
+					FontSize--;
 				if(int Result = DoButton_Ex(&m_Map.m_lGroups[g], aBuf, g==m_SelectedGroup, &Slot,
-					BUTTON_CONTEXT, "Select group. Right click for properties.", 0))
+					BUTTON_CONTEXT, m_Map.m_lGroups[g]->m_Collapse ? "Select group. Double click to expand." : "Select group. Double click to collapse.", 0, FontSize))
 				{
 					m_SelectedGroup = g;
 					m_SelectedLayer = 0;
 
 					static int s_GroupPopupId = 0;
 					if(Result == 2)
-						UiInvokePopupMenu(&s_GroupPopupId, 0, UI()->MouseX(), UI()->MouseY(), 120, 200, PopupGroup);
+						UiInvokePopupMenu(&s_GroupPopupId, 0, UI()->MouseX(), UI()->MouseY(), 120, 220, PopupGroup);
+
+					if(m_Map.m_lGroups[g]->m_lLayers.size() && Input()->MouseDoubleClick())
+						m_Map.m_lGroups[g]->m_Collapse ^= 1;
 				}
 				LayersBox.HSplitTop(2.0f, &Slot, &LayersBox);
 			}
@@ -1840,6 +2071,9 @@ void CEditor::RenderLayers(CUIRect ToolBox, CUIRect ToolBar, CUIRect View)
 					continue;
 				}
 
+				if(m_Map.m_lGroups[g]->m_Collapse)
+					continue;
+
 				//visible
 				LayersBox.HSplitTop(12.0f, &Slot, &LayersBox);
 				Slot.VSplitLeft(12.0f, 0, &Button);
@@ -1853,15 +2087,24 @@ void CEditor::RenderLayers(CUIRect ToolBox, CUIRect ToolBar, CUIRect View)
 					if(m_Map.m_lGroups[g]->m_lLayers[i] != m_Map.m_pGameLayer)
 						m_Map.m_lGroups[g]->m_lLayers[i]->m_SaveToMap = !m_Map.m_lGroups[g]->m_lLayers[i]->m_SaveToMap;
 
-				str_format(aBuf, sizeof(aBuf),"#%d %s ", i, m_Map.m_lGroups[g]->m_lLayers[i]->m_pTypeName);
+				if(m_Map.m_lGroups[g]->m_lLayers[i]->m_aName[0])
+					str_format(aBuf, sizeof(aBuf), "%s", m_Map.m_lGroups[g]->m_lLayers[i]->m_aName);
+				else if(m_Map.m_lGroups[g]->m_lLayers[i]->m_Type == LAYERTYPE_TILES)
+					str_copy(aBuf, "Tiles", sizeof(aBuf));
+				else
+					str_copy(aBuf, "Quads", sizeof(aBuf));
+
+				float FontSize = 10.0f;
+				while(TextRender()->TextWidth(0, FontSize, aBuf, -1) > Button.w)
+					FontSize--;
 				if(int Result = DoButton_Ex(m_Map.m_lGroups[g]->m_lLayers[i], aBuf, g==m_SelectedGroup&&i==m_SelectedLayer, &Button,
-					BUTTON_CONTEXT, "Select layer. Right click for properties.", 0))
+					BUTTON_CONTEXT, "Select layer.", 0, FontSize))
 				{
 					m_SelectedLayer = i;
 					m_SelectedGroup = g;
 					static int s_LayerPopupID = 0;
 					if(Result == 2)
-						UiInvokePopupMenu(&s_LayerPopupID, 0, UI()->MouseX(), UI()->MouseY(), 120, 220, PopupLayer);
+						UiInvokePopupMenu(&s_LayerPopupID, 0, UI()->MouseX(), UI()->MouseY(), 120, 245, PopupLayer);
 				}
 
 				LayerCur += 14.0f;
@@ -1899,6 +2142,7 @@ void CEditor::ReplaceImage(const char *pFileName, int StorageType, void *pUser)
 	*pImg = ImgInfo;
 	pImg->m_External = External;
 	pEditor->ExtractName(pFileName, pImg->m_aName, sizeof(pImg->m_aName));
+	pImg->m_AutoMapper.Load(pImg->m_aName);
 	pImg->m_TexID = pEditor->Graphics()->LoadTextureRaw(ImgInfo.m_Width, ImgInfo.m_Height, ImgInfo.m_Format, ImgInfo.m_pData, CImageInfo::FORMAT_AUTO, 0);
 	pEditor->SortImages();
 	for(int i = 0; i < pEditor->m_Map.m_lImages.size(); ++i)
@@ -1930,6 +2174,7 @@ void CEditor::AddImage(const char *pFileName, int StorageType, void *pUser)
 	pImg->m_TexID = pEditor->Graphics()->LoadTextureRaw(ImgInfo.m_Width, ImgInfo.m_Height, ImgInfo.m_Format, ImgInfo.m_pData, CImageInfo::FORMAT_AUTO, 0);
 	pImg->m_External = 1;	// external by default
 	str_copy(pImg->m_aName, aBuf, sizeof(pImg->m_aName));
+	pImg->m_AutoMapper.Load(pImg->m_aName);
 	pEditor->m_Map.m_lImages.add(pImg);
 	pEditor->SortImages();
 	if(pEditor->m_SelectedImage > -1 && pEditor->m_SelectedImage < pEditor->m_Map.m_lImages.size())
@@ -2063,6 +2308,20 @@ void CEditor::RenderImages(CUIRect ToolBox, CUIRect ToolBar, CUIRect View)
 		ToolBox.VSplitRight(3.0f, &ToolBox, 0);	// extra spacing
 		Scroll.HMargin(5.0f, &Scroll);
 		s_ScrollValue = UiDoScrollbarV(&s_ScrollBar, &Scroll, s_ScrollValue);
+
+		if(UI()->MouseInside(&Scroll) || UI()->MouseInside(&ToolBox))
+		{
+			int ScrollNum = (int)((ImagesHeight-ToolBox.h)/14.0f)+1;
+			if(ScrollNum > 0)
+			{
+				if(Input()->KeyPresses(KEY_MOUSE_WHEEL_UP))
+					s_ScrollValue = clamp(s_ScrollValue - 1.0f/ScrollNum, 0.0f, 1.0f);
+				if(Input()->KeyPresses(KEY_MOUSE_WHEEL_DOWN))
+					s_ScrollValue = clamp(s_ScrollValue + 1.0f/ScrollNum, 0.0f, 1.0f);
+			}
+			else
+				ScrollNum = 0;
+		}
 	}
 
 	float ImageStartAt = ScrollDifference * s_ScrollValue;
@@ -2244,9 +2503,9 @@ void CEditor::RenderFileDialog()
 	// filebox
 	if(m_FileDialogStorageType == IStorage::TYPE_SAVE)
 	{
-		static int s_FileBoxID = 0;
+		static float s_FileBoxID = 0;
 		UI()->DoLabel(&FileBoxLabel, "Filename:", 10.0f, -1, -1);
-		if(DoEditBox(&s_FileBoxID, &FileBox, m_aFileDialogFileName, sizeof(m_aFileDialogFileName), 10.0f))
+		if(DoEditBox(&s_FileBoxID, &FileBox, m_aFileDialogFileName, sizeof(m_aFileDialogFileName), 10.0f, &s_FileBoxID))
 		{
 			// remove '/' and '\'
 			for(int i = 0; m_aFileDialogFileName[i]; ++i)
@@ -2595,8 +2854,8 @@ void CEditor::RenderEnvelopeEditor(CUIRect View)
 
 			ToolBar.VSplitLeft(80.0f, &Button, &ToolBar);
 
-			static int s_NameBox = 0;
-			if(DoEditBox(&s_NameBox, &Button, pEnvelope->m_aName, sizeof(pEnvelope->m_aName), 10.0f))
+			static float s_NameBox = 0;
+			if(DoEditBox(&s_NameBox, &Button, pEnvelope->m_aName, sizeof(pEnvelope->m_aName), 10.0f, &s_NameBox))
 				m_Map.m_Modified = true;
 		}
 	}
@@ -3055,6 +3314,18 @@ void CEditor::Render()
 	if(m_Mode == MODE_LAYERS)
 		DoMapEditor(View, ToolBar);
 
+	// do the scrolling
+	if(m_Dialog == DIALOG_NONE && UI()->MouseInside(&View))
+	{
+		if(Input()->KeyPresses(KEY_MOUSE_WHEEL_UP))
+			m_ZoomLevel -= 20;
+
+		if(Input()->KeyPresses(KEY_MOUSE_WHEEL_DOWN))
+			m_ZoomLevel += 20;
+
+		m_ZoomLevel = clamp(m_ZoomLevel, 50, 2000);
+	}
+
 	if(m_GuiActive)
 	{
 		float Brightness = 0.25f;
@@ -3152,7 +3423,6 @@ void CEditor::Render()
 		Graphics()->QuadsDrawTL(&QuadItem, 1);
 		Graphics()->QuadsEnd();
 	}
-
 }
 
 void CEditor::Reset(bool CreateDefault)
@@ -3190,6 +3460,24 @@ void CEditor::Reset(bool CreateDefault)
 	m_Map.m_Modified = false;
 }
 
+int CEditor::GetLineDistance()
+{
+	int LineDistance = 512;
+
+	if(m_ZoomLevel <= 100)
+		LineDistance = 16;
+	else if(m_ZoomLevel <= 250)
+		LineDistance = 32;
+	else if(m_ZoomLevel <= 450)
+		LineDistance = 64;
+	else if(m_ZoomLevel <= 850)
+		LineDistance = 128;
+	else if(m_ZoomLevel <= 1550)
+		LineDistance = 256;
+
+	return LineDistance;
+}
+
 void CEditorMap::DeleteEnvelope(int Index)
 {
 	if(Index < 0 || Index >= m_lEnvelopes.size())
@@ -3230,7 +3518,7 @@ void CEditorMap::MakeGameGroup(CLayerGroup *pGroup)
 {
 	m_pGameGroup = pGroup;
 	m_pGameGroup->m_GameGroup = true;
-	m_pGameGroup->m_pName = "Game";
+	str_copy(m_pGameGroup->m_aName, "Game", sizeof(m_pGameGroup->m_aName));
 }
 
 
@@ -3337,6 +3625,7 @@ void CEditor::UpdateAndRender()
 	float rx, ry;
 	{
 		Input()->MouseRelative(&rx, &ry);
+		UI()->ConvertMouseMove(&rx, &ry);
 		m_MouseDeltaX = rx;
 		m_MouseDeltaY = ry;
 
diff --git a/src/game/editor/editor.h b/src/game/editor/editor.h
index c7779954..1a904953 100644
--- a/src/game/editor/editor.h
+++ b/src/game/editor/editor.h
@@ -3,23 +3,26 @@
 #ifndef GAME_EDITOR_EDITOR_H
 #define GAME_EDITOR_EDITOR_H
 
-#include <base/system.h>
+#include <math.h>
+
 #include <base/math.h>
-#include <base/tl/array.h>
+#include <base/system.h>
+
 #include <base/tl/algorithm.h>
+#include <base/tl/array.h>
 #include <base/tl/sorted_array.h>
 #include <base/tl/string.h>
 
-#include <math.h>
+#include <game/client/ui.h>
 #include <game/mapitems.h>
 #include <game/client/render.h>
 
-#include <engine/shared/datafile.h>
 #include <engine/shared/config.h>
+#include <engine/shared/datafile.h>
 #include <engine/editor.h>
 #include <engine/graphics.h>
 
-#include <game/client/ui.h>
+#include "auto_map.h"
 
 typedef void (*INDEX_MODIFY_FUNC)(int *pIndex);
 
@@ -123,7 +126,7 @@ public:
 	CLayer()
 	{
 		m_Type = LAYERTYPE_INVALID;
-		m_pTypeName = "(invalid)";
+		str_copy(m_aName, "(invalid)", sizeof(m_aName));
 		m_Visible = true;
 		m_Readonly = false;
 		m_SaveToMap = true;
@@ -153,7 +156,7 @@ public:
 
 	virtual void GetSize(float *w, float *h) { *w = 0; *h = 0;}
 
-	const char *m_pTypeName;
+	char m_aName[12];
 	int m_Type;
 	int m_Flags;
 
@@ -181,10 +184,11 @@ public:
 	int m_ClipW;
 	int m_ClipH;
 
-	const char *m_pName;
+	char m_aName[12];
 	bool m_GameGroup;
 	bool m_Visible;
 	bool m_SaveToMap;
+	bool m_Collapse;
 
 	CLayerGroup();
 	~CLayerGroup();
@@ -230,6 +234,7 @@ public:
 	CEditor *m_pEditor;
 
 	CEditorImage(CEditor *pEditor)
+	: m_AutoMapper(pEditor)
 	{
 		m_pEditor = pEditor;
 		m_TexID = -1;
@@ -249,6 +254,7 @@ public:
 	int m_External;
 	char m_aName[128];
 	unsigned char m_aTileFlags[256];
+	class CAutoMapper m_AutoMapper;
 };
 
 class CEditorMap
@@ -400,6 +406,8 @@ public:
 	int m_Width;
 	int m_Height;
 	CColor m_Color;
+	int m_ColorEnv;
+	int m_ColorEnvOffset;
 	CTile *m_pTiles;
 };
 
@@ -470,6 +478,9 @@ public:
 		m_Dialog = 0;
 		m_pTooltip = 0;
 
+		m_GridActive = false;
+		m_GridFactor = 1;
+
 		m_aFileName[0] = 0;
 		m_aFileSaveName[0] = 0;
 		m_ValidSaveFilename = false;
@@ -551,6 +562,9 @@ public:
 	int m_Dialog;
 	const char *m_pTooltip;
 
+	bool m_GridActive;
+	int m_GridFactor;
+
 	char m_aFileName[512];
 	char m_aFileSaveName[512];
 	bool m_ValidSaveFilename;
@@ -651,12 +665,14 @@ public:
 
 	CEditorMap m_Map;
 
+	static void EnvelopeEval(float TimeOffset, int Env, float *pChannels, void *pUser);
+
 	void DoMapBorder();
 	int DoButton_Editor_Common(const void *pID, const char *pText, int Checked, const CUIRect *pRect, int Flags, const char *pToolTip);
 	int DoButton_Editor(const void *pID, const char *pText, int Checked, const CUIRect *pRect, int Flags, const char *pToolTip);
 
 	int DoButton_Tab(const void *pID, const char *pText, int Checked, const CUIRect *pRect, int Flags, const char *pToolTip);
-	int DoButton_Ex(const void *pID, const char *pText, int Checked, const CUIRect *pRect, int Flags, const char *pToolTip, int Corners);
+	int DoButton_Ex(const void *pID, const char *pText, int Checked, const CUIRect *pRect, int Flags, const char *pToolTip, int Corners, float FontSize=10.0f);
 	int DoButton_ButtonDec(const void *pID, const char *pText, int Checked, const CUIRect *pRect, int Flags, const char *pToolTip);
 	int DoButton_ButtonInc(const void *pID, const char *pText, int Checked, const CUIRect *pRect, int Flags, const char *pToolTip);
 
@@ -665,10 +681,12 @@ public:
 	int DoButton_Menu(const void *pID, const char *pText, int Checked, const CUIRect *pRect, int Flags, const char *pToolTip);
 	int DoButton_MenuItem(const void *pID, const char *pText, int Checked, const CUIRect *pRect, int Flags=0, const char *pToolTip=0);
 
-	int DoEditBox(void *pID, const CUIRect *pRect, char *pStr, unsigned StrSize, float FontSize, bool Hidden=false);
+	int DoEditBox(void *pID, const CUIRect *pRect, char *pStr, unsigned StrSize, float FontSize, float *Offset, bool Hidden=false, int Corners=CUI::CORNER_ALL);
 
 	void RenderBackground(CUIRect View, int Texture, float Size, float Brightness);
 
+	void RenderGrid(CLayerGroup *pGroup);
+
 	void UiInvokePopupMenu(void *pID, int Flags, float X, float Y, float W, float H, int (*pfnFunc)(CEditor *pEditor, CUIRect Rect), void *pExtra=0);
 	void UiDoPopupMenu();
 
@@ -684,6 +702,7 @@ public:
 	static int PopupSelectGametileOp(CEditor *pEditor, CUIRect View);
 	static int PopupImage(CEditor *pEditor, CUIRect View);
 	static int PopupMenuFile(CEditor *pEditor, CUIRect View);
+	static int PopupSelectConfigAutoMap(CEditor *pEditor, CUIRect View);
 
 	static void CallbackOpenMap(const char *pFileName, int StorageType, void *pUser);
 	static void CallbackAppendMap(const char *pFileName, int StorageType, void *pUser);
@@ -694,6 +713,9 @@ public:
 
 	void PopupSelectGametileOpInvoke(float x, float y);
 	int PopupSelectGameTileOpResult();
+	
+	void PopupSelectConfigAutoMapInvoke(float x, float y);
+	int PopupSelectConfigAutoMapResult();
 
 	vec4 ButtonColorMul(const void *pID);
 
@@ -733,6 +755,8 @@ public:
 		int Length = pEnd > pExtractedName ? min(BufferSize, (int)(pEnd-pExtractedName+1)) : BufferSize;
 		str_copy(pName, pExtractedName, Length);
 	}
+
+	int GetLineDistance();
 };
 
 // make sure to inline this function
diff --git a/src/game/editor/io.cpp b/src/game/editor/io.cpp
index 7207e49f..68330f03 100644
--- a/src/game/editor/io.cpp
+++ b/src/game/editor/io.cpp
@@ -266,6 +266,9 @@ int CEditorMap::Save(class IStorage *pStorage, const char *pFileName)
 		GItem.m_StartLayer = LayerCount;
 		GItem.m_NumLayers = 0;
 
+		// save group name
+		StrToInts(GItem.m_aName, sizeof(GItem.m_aName)/sizeof(int), pGroup->m_aName);
+
 		for(int l = 0; l < pGroup->m_lLayers.size(); l++)
 		{
 			if(!pGroup->m_lLayers[l]->m_SaveToMap)
@@ -278,23 +281,24 @@ int CEditorMap::Save(class IStorage *pStorage, const char *pFileName)
 				pLayer->PrepareForSave();
 
 				CMapItemLayerTilemap Item;
-				Item.m_Version = 2;
+				Item.m_Version = 3;
 
 				Item.m_Layer.m_Flags = pLayer->m_Flags;
 				Item.m_Layer.m_Type = pLayer->m_Type;
 
-				Item.m_Color.r = pLayer->m_Color.r;
-				Item.m_Color.g = pLayer->m_Color.g;
-				Item.m_Color.b = pLayer->m_Color.b;
-				Item.m_Color.a = pLayer->m_Color.a;
-				Item.m_ColorEnv = -1; // not in use right now
-				Item.m_ColorEnvOffset = 0;
+				Item.m_Color = pLayer->m_Color;
+				Item.m_ColorEnv = pLayer->m_ColorEnv;
+				Item.m_ColorEnvOffset = pLayer->m_ColorEnvOffset;
 
 				Item.m_Width = pLayer->m_Width;
 				Item.m_Height = pLayer->m_Height;
-				Item.m_Flags = pLayer->m_Game;
+				Item.m_Flags = pLayer->m_Game ? TILESLAYERFLAG_GAME : 0;
 				Item.m_Image = pLayer->m_Image;
 				Item.m_Data = df.AddData(pLayer->m_Width*pLayer->m_Height*sizeof(CTile), pLayer->m_pTiles);
+
+				// save layer name
+				StrToInts(Item.m_aName, sizeof(Item.m_aName)/sizeof(int), pLayer->m_aName);
+
 				df.AddItem(MAPITEMTYPE_LAYER, LayerCount, sizeof(Item), &Item);
 
 				GItem.m_NumLayers++;
@@ -307,7 +311,7 @@ int CEditorMap::Save(class IStorage *pStorage, const char *pFileName)
 				if(pLayer->m_lQuads.size())
 				{
 					CMapItemLayerQuads Item;
-					Item.m_Version = 1;
+					Item.m_Version = 2;
 					Item.m_Layer.m_Flags = pLayer->m_Flags;
 					Item.m_Layer.m_Type = pLayer->m_Type;
 					Item.m_Image = pLayer->m_Image;
@@ -315,6 +319,10 @@ int CEditorMap::Save(class IStorage *pStorage, const char *pFileName)
 					// add the data
 					Item.m_NumQuads = pLayer->m_lQuads.size();
 					Item.m_Data = df.AddDataSwapped(pLayer->m_lQuads.size()*sizeof(CQuad), pLayer->m_lQuads.base_ptr());
+
+					// save layer name
+					StrToInts(Item.m_aName, sizeof(Item.m_aName)/sizeof(int), pLayer->m_aName);
+
 					df.AddItem(MAPITEMTYPE_LAYER, LayerCount, sizeof(Item), &Item);
 
 					// clean up
@@ -449,6 +457,9 @@ int CEditorMap::Load(class IStorage *pStorage, const char *pFileName, int Storag
 				if(pName)
 					str_copy(pImg->m_aName, pName, 128);
 
+				// load auto mapper file
+				pImg->m_AutoMapper.Load(pImg->m_aName);
+
 				m_lImages.add(pImg);
 
 				// unload image
@@ -486,6 +497,10 @@ int CEditorMap::Load(class IStorage *pStorage, const char *pFileName, int Storag
 					pGroup->m_ClipH = pGItem->m_ClipH;
 				}
 
+				// load group name
+				if(pGItem->m_Version >= 3)
+					IntsToStr(pGItem->m_aName, sizeof(pGroup->m_aName)/sizeof(int), pGroup->m_aName);
+
 				for(int l = 0; l < pGItem->m_NumLayers; l++)
 				{
 					CLayer *pLayer = 0;
@@ -498,7 +513,7 @@ int CEditorMap::Load(class IStorage *pStorage, const char *pFileName, int Storag
 						CMapItemLayerTilemap *pTilemapItem = (CMapItemLayerTilemap *)pLayerItem;
 						CLayerTiles *pTiles = 0;
 
-						if(pTilemapItem->m_Flags&1)
+						if(pTilemapItem->m_Flags&TILESLAYERFLAG_GAME)
 						{
 							pTiles = new CLayerGame(pTilemapItem->m_Width, pTilemapItem->m_Height);
 							MakeGameLayer(pTiles);
@@ -508,10 +523,9 @@ int CEditorMap::Load(class IStorage *pStorage, const char *pFileName, int Storag
 						{
 							pTiles = new CLayerTiles(pTilemapItem->m_Width, pTilemapItem->m_Height);
 							pTiles->m_pEditor = m_pEditor;
-							pTiles->m_Color.r = pTilemapItem->m_Color.r;
-							pTiles->m_Color.g = pTilemapItem->m_Color.g;
-							pTiles->m_Color.b = pTilemapItem->m_Color.b;
-							pTiles->m_Color.a = pTilemapItem->m_Color.a;
+							pTiles->m_Color = pTilemapItem->m_Color;
+							pTiles->m_ColorEnv = pTilemapItem->m_ColorEnv;
+							pTiles->m_ColorEnvOffset = pTilemapItem->m_ColorEnvOffset;
 						}
 
 						pLayer = pTiles;
@@ -519,7 +533,11 @@ int CEditorMap::Load(class IStorage *pStorage, const char *pFileName, int Storag
 						pGroup->AddLayer(pTiles);
 						void *pData = DataFile.GetData(pTilemapItem->m_Data);
 						pTiles->m_Image = pTilemapItem->m_Image;
-						pTiles->m_Game = pTilemapItem->m_Flags&1;
+						pTiles->m_Game = pTilemapItem->m_Flags&TILESLAYERFLAG_GAME;
+
+						// load layer name
+						if(pTilemapItem->m_Version >= 3)
+							IntsToStr(pTilemapItem->m_aName, sizeof(pTiles->m_aName)/sizeof(int), pTiles->m_aName);
 
 						mem_copy(pTiles->m_pTiles, pData, pTiles->m_Width*pTiles->m_Height*sizeof(CTile));
 
@@ -543,6 +561,11 @@ int CEditorMap::Load(class IStorage *pStorage, const char *pFileName, int Storag
 						pQuads->m_Image = pQuadsItem->m_Image;
 						if(pQuads->m_Image < -1 || pQuads->m_Image >= m_lImages.size())
 							pQuads->m_Image = -1;
+
+						// load layer name
+						if(pQuadsItem->m_Version >= 2)
+							IntsToStr(pQuadsItem->m_aName, sizeof(pQuads->m_aName)/sizeof(int), pQuads->m_aName);
+
 						void *pData = DataFile.GetDataSwapped(pQuadsItem->m_Data);
 						pGroup->AddLayer(pQuads);
 						pQuads->m_lQuads.set_size(pQuadsItem->m_NumQuads);
diff --git a/src/game/editor/layer_game.cpp b/src/game/editor/layer_game.cpp
index f4a5fb76..7e879c3e 100644
--- a/src/game/editor/layer_game.cpp
+++ b/src/game/editor/layer_game.cpp
@@ -6,7 +6,7 @@
 CLayerGame::CLayerGame(int w, int h)
 : CLayerTiles(w, h)
 {
-	m_pTypeName = "Game";
+	str_copy(m_aName, "Game", sizeof(m_aName));
 	m_Game = 1;
 }
 
diff --git a/src/game/editor/layer_quads.cpp b/src/game/editor/layer_quads.cpp
index d2a8a1e5..d0b66405 100644
--- a/src/game/editor/layer_quads.cpp
+++ b/src/game/editor/layer_quads.cpp
@@ -13,7 +13,7 @@
 CLayerQuads::CLayerQuads()
 {
 	m_Type = LAYERTYPE_QUADS;
-	m_pTypeName = "Quads";
+	str_copy(m_aName, "Quads", sizeof(m_aName));
 	m_Image = -1;
 }
 
@@ -21,31 +21,13 @@ CLayerQuads::~CLayerQuads()
 {
 }
 
-static void EnvelopeEval(float TimeOffset, int Env, float *pChannels, void *pUser)
-{
-	CEditor *pEditor = (CEditor *)pUser;
-	if(Env < 0 || Env > pEditor->m_Map.m_lEnvelopes.size())
-	{
-		pChannels[0] = 0;
-		pChannels[1] = 0;
-		pChannels[2] = 0;
-		pChannels[3] = 0;
-		return;
-	}
-
-	CEnvelope *e = pEditor->m_Map.m_lEnvelopes[Env];
-	float t = pEditor->m_AnimateTime+TimeOffset;
-	t *= pEditor->m_AnimateSpeed;
-	e->Eval(t, pChannels);
-}
-
 void CLayerQuads::Render()
 {
 	Graphics()->TextureSet(-1);
 	if(m_Image >= 0 && m_Image < m_pEditor->m_Map.m_lImages.size())
 		Graphics()->TextureSet(m_pEditor->m_Map.m_lImages[m_Image]->m_TexID);
 
-	m_pEditor->RenderTools()->RenderQuads(m_lQuads.base_ptr(), m_lQuads.size(), LAYERRENDERFLAG_OPAQUE|LAYERRENDERFLAG_TRANSPARENT, EnvelopeEval, m_pEditor);
+	m_pEditor->RenderTools()->RenderQuads(m_lQuads.base_ptr(), m_lQuads.size(), LAYERRENDERFLAG_OPAQUE|LAYERRENDERFLAG_TRANSPARENT, m_pEditor->EnvelopeEval, m_pEditor);
 }
 
 CQuad *CLayerQuads::NewQuad()
diff --git a/src/game/editor/layer_tiles.cpp b/src/game/editor/layer_tiles.cpp
index b792eda9..5662613c 100644
--- a/src/game/editor/layer_tiles.cpp
+++ b/src/game/editor/layer_tiles.cpp
@@ -15,7 +15,7 @@
 CLayerTiles::CLayerTiles(int w, int h)
 {
 	m_Type = LAYERTYPE_TILES;
-	m_pTypeName = "Tiles";
+	str_copy(m_aName, "Tiles", sizeof(m_aName));
 	m_Width = w;
 	m_Height = h;
 	m_Image = -1;
@@ -25,6 +25,8 @@ CLayerTiles::CLayerTiles(int w, int h)
 	m_Color.g = 255;
 	m_Color.b = 255;
 	m_Color.a = 255;
+	m_ColorEnv = -1;
+	m_ColorEnvOffset = 0;
 
 	m_pTiles = new CTile[m_Width*m_Height];
 	mem_zero(m_pTiles, m_Width*m_Height*sizeof(CTile));
@@ -62,7 +64,8 @@ void CLayerTiles::Render()
 		m_TexID = m_pEditor->m_Map.m_lImages[m_Image]->m_TexID;
 	Graphics()->TextureSet(m_TexID);
 	vec4 Color = vec4(m_Color.r/255.0f, m_Color.g/255.0f, m_Color.b/255.0f, m_Color.a/255.0f);
-	m_pEditor->RenderTools()->RenderTilemap(m_pTiles, m_Width, m_Height, 32.0f, Color, LAYERRENDERFLAG_OPAQUE|LAYERRENDERFLAG_TRANSPARENT);
+	m_pEditor->RenderTools()->RenderTilemap(m_pTiles, m_Width, m_Height, 32.0f, Color, LAYERRENDERFLAG_OPAQUE|LAYERRENDERFLAG_TRANSPARENT,
+												m_pEditor->EnvelopeEval, m_pEditor, m_ColorEnv, m_ColorEnvOffset);
 }
 
 int CLayerTiles::ConvertX(float x) const { return (int)(x/32.0f); }
@@ -360,14 +363,32 @@ void CLayerTiles::ShowInfo()
 int CLayerTiles::RenderProperties(CUIRect *pToolBox)
 {
 	CUIRect Button;
-	pToolBox->HSplitBottom(12.0f, pToolBox, &Button);
-
+	
 	bool InGameGroup = !find_linear(m_pEditor->m_Map.m_pGameGroup->m_lLayers.all(), this).empty();
-	if(m_pEditor->m_Map.m_pGameLayer == this)
+	if(m_pEditor->m_Map.m_pGameLayer != this)
+	{
+		if(m_Image >= 0 && m_Image < m_pEditor->m_Map.m_lImages.size() && m_pEditor->m_Map.m_lImages[m_Image]->m_AutoMapper.IsLoaded())
+		{
+			static int s_AutoMapperButton = 0;
+			pToolBox->HSplitBottom(12.0f, pToolBox, &Button);
+			if(m_pEditor->DoButton_Editor(&s_AutoMapperButton, "Auto map", 0, &Button, 0, ""))
+				m_pEditor->PopupSelectConfigAutoMapInvoke(m_pEditor->UI()->MouseX(), m_pEditor->UI()->MouseY());
+			
+			int Result = m_pEditor->PopupSelectConfigAutoMapResult();
+			if(Result > -1)
+			{
+				m_pEditor->m_Map.m_lImages[m_Image]->m_AutoMapper.Proceed(this, Result);
+				return 1;
+			}
+		}
+	}
+	else
 		InGameGroup = false;
 
 	if(InGameGroup)
 	{
+		pToolBox->HSplitBottom(2.0f, pToolBox, 0);
+		pToolBox->HSplitBottom(12.0f, pToolBox, &Button);
 		static int s_ColclButton = 0;
 		if(m_pEditor->DoButton_Editor(&s_ColclButton, "Game tiles", 0, &Button, 0, "Constructs game tiles from this layer"))
 			m_pEditor->PopupSelectGametileOpInvoke(m_pEditor->UI()->MouseX(), m_pEditor->UI()->MouseY());
@@ -394,6 +415,8 @@ int CLayerTiles::RenderProperties(CUIRect *pToolBox)
 		PROP_SHIFT,
 		PROP_IMAGE,
 		PROP_COLOR,
+		PROP_COLOR_ENV,
+		PROP_COLOR_ENV_OFFSET,
 		NUM_PROPS,
 	};
 
@@ -409,6 +432,8 @@ int CLayerTiles::RenderProperties(CUIRect *pToolBox)
 		{"Shift", 0, PROPTYPE_SHIFT, 0, 0},
 		{"Image", m_Image, PROPTYPE_IMAGE, 0, 0},
 		{"Color", Color, PROPTYPE_COLOR, 0, 0},
+		{"Color Env", m_ColorEnv+1, PROPTYPE_INT_STEP, 0, m_pEditor->m_Map.m_lEnvelopes.size()+1},
+		{"Color TO", m_ColorEnvOffset, PROPTYPE_INT_SCROLL, -1000000, 1000000},
 		{0},
 	};
 
@@ -447,6 +472,10 @@ int CLayerTiles::RenderProperties(CUIRect *pToolBox)
 		m_Color.b = (NewVal>>8)&0xff;
 		m_Color.a = NewVal&0xff;
 	}
+	if(Prop == PROP_COLOR_ENV)
+		m_ColorEnv = clamp(NewVal-1, -1, m_pEditor->m_Map.m_lEnvelopes.size()-1);
+	if(Prop == PROP_COLOR_ENV_OFFSET)
+		m_ColorEnvOffset = NewVal;
 
 	return 0;
 }
diff --git a/src/game/editor/popups.cpp b/src/game/editor/popups.cpp
index 3ae29725..f29ae7e2 100644
--- a/src/game/editor/popups.cpp
+++ b/src/game/editor/popups.cpp
@@ -1,10 +1,14 @@
 /* (c) Magnus Auvinen. See licence.txt in the root of the distribution for more information. */
 /* If you are missing that file, acquire a complete release at teeworlds.com.                */
+
+#include <base/tl/array.h>
+
 #include <engine/console.h>
 #include <engine/graphics.h>
 #include <engine/input.h>
 #include <engine/keys.h>
 #include <engine/storage.h>
+
 #include "editor.h"
 
 
@@ -147,6 +151,7 @@ int CEditor::PopupGroup(CEditor *pEditor, CUIRect View)
 		l->m_pEditor = pEditor;
 		pEditor->m_Map.m_lGroups[pEditor->m_SelectedGroup]->AddLayer(l);
 		pEditor->m_SelectedLayer = pEditor->m_Map.m_lGroups[pEditor->m_SelectedGroup]->m_lLayers.size()-1;
+		pEditor->m_Map.m_lGroups[pEditor->m_SelectedGroup]->m_Collapse = false;
 		return 1;
 	}
 
@@ -160,9 +165,22 @@ int CEditor::PopupGroup(CEditor *pEditor, CUIRect View)
 		l->m_pEditor = pEditor;
 		pEditor->m_Map.m_lGroups[pEditor->m_SelectedGroup]->AddLayer(l);
 		pEditor->m_SelectedLayer = pEditor->m_Map.m_lGroups[pEditor->m_SelectedGroup]->m_lLayers.size()-1;
+		pEditor->m_Map.m_lGroups[pEditor->m_SelectedGroup]->m_Collapse = false;
 		return 1;
 	}
 
+	// group name
+	if(!pEditor->GetSelectedGroup()->m_GameGroup)
+	{
+		View.HSplitBottom(5.0f, &View, &Button);
+		View.HSplitBottom(12.0f, &View, &Button);
+		static float s_Name = 0;
+		pEditor->UI()->DoLabel(&Button, "Name:", 10.0f, -1, -1);
+		Button.VSplitLeft(40.0f, 0, &Button);
+		if(pEditor->DoEditBox(&s_Name, &Button, pEditor->m_Map.m_lGroups[pEditor->m_SelectedGroup]->m_aName, sizeof(pEditor->m_Map.m_lGroups[pEditor->m_SelectedGroup]->m_aName), 10.0f, &s_Name))
+			pEditor->m_Map.m_Modified = true;
+	}
+
 	enum
 	{
 		PROP_ORDER=0,
@@ -239,6 +257,18 @@ int CEditor::PopupLayer(CEditor *pEditor, CUIRect View)
 		return 1;
 	}
 
+	// layer name
+	if(pEditor->m_Map.m_pGameLayer != pEditor->GetSelectedLayer(0))
+	{
+		View.HSplitBottom(5.0f, &View, &Button);
+		View.HSplitBottom(12.0f, &View, &Button);
+		static float s_Name = 0;
+		pEditor->UI()->DoLabel(&Button, "Name:", 10.0f, -1, -1);
+		Button.VSplitLeft(40.0f, 0, &Button);
+		if(pEditor->DoEditBox(&s_Name, &Button, pEditor->GetSelectedLayer(0)->m_aName, sizeof(pEditor->GetSelectedLayer(0)->m_aName), 10.0f, &s_Name))
+			pEditor->m_Map.m_Modified = true;
+	}
+
 	View.HSplitBottom(10.0f, &View, 0);
 
 	CLayerGroup *pCurrentGroup = pEditor->m_Map.m_lGroups[pEditor->m_SelectedGroup];
@@ -528,8 +558,8 @@ int CEditor::PopupNewFolder(CEditor *pEditor, CUIRect View)
 		View.HSplitBottom(40.0f, &View, 0);
 		View.VMargin(40.0f, &View);
 		View.HSplitBottom(20.0f, &View, &Label);
-		static int s_FolderBox = 0;
-		pEditor->DoEditBox(&s_FolderBox, &Label, pEditor->m_FileDialogNewFolderName, sizeof(pEditor->m_FileDialogNewFolderName), 15.0f);
+		static float s_FolderBox = 0;
+		pEditor->DoEditBox(&s_FolderBox, &Label, pEditor->m_FileDialogNewFolderName, sizeof(pEditor->m_FileDialogNewFolderName), 15.0f, &s_FolderBox);
 		View.HSplitBottom(20.0f, &View, &Label);
 		pEditor->UI()->DoLabel(&Label, "Name:", 10.0f, -1);
 
@@ -737,3 +767,43 @@ int CEditor::PopupSelectGameTileOpResult()
 	s_GametileOpSelected = -1;
 	return Result;
 }
+
+static int s_AutoMapConfigSelected = -1;
+
+int CEditor::PopupSelectConfigAutoMap(CEditor *pEditor, CUIRect View)
+{
+	CLayerTiles *pLayer = static_cast<CLayerTiles*>(pEditor->GetSelectedLayer(0));
+	CUIRect Button;
+	static int s_AutoMapperConfigButtons[256];
+	CAutoMapper *pAutoMapper = &pEditor->m_Map.m_lImages[pLayer->m_Image]->m_AutoMapper;
+	
+	for(int i = 0; i < pAutoMapper->ConfigNamesNum(); ++i)
+	{
+		View.HSplitTop(2.0f, 0, &View);
+		View.HSplitTop(12.0f, &Button, &View);
+		if(pEditor->DoButton_Editor(&s_AutoMapperConfigButtons[i], pAutoMapper->GetConfigName(i), 0, &Button, 0, 0))
+			s_AutoMapConfigSelected = i;
+	}
+
+	return 0;
+}
+
+void CEditor::PopupSelectConfigAutoMapInvoke(float x, float y)
+{
+	static int s_AutoMapConfigSelectID = 0;
+	s_AutoMapConfigSelected = -1;
+	CLayerTiles *pLayer = static_cast<CLayerTiles*>(GetSelectedLayer(0));
+	if(pLayer && pLayer->m_Image >= 0 && pLayer->m_Image < m_Map.m_lImages.size() &&
+		m_Map.m_lImages[pLayer->m_Image]->m_AutoMapper.ConfigNamesNum())
+		UiInvokePopupMenu(&s_AutoMapConfigSelectID, 0, x, y, 120.0f, 12.0f+14.0f*m_Map.m_lImages[pLayer->m_Image]->m_AutoMapper.ConfigNamesNum(), PopupSelectConfigAutoMap);
+}
+
+int CEditor::PopupSelectConfigAutoMapResult()
+{
+	if(s_AutoMapConfigSelected < 0)
+		return -1;
+	
+	int Result = s_AutoMapConfigSelected;
+	s_AutoMapConfigSelected = -1;
+	return Result;
+}
diff --git a/src/game/gamecore.cpp b/src/game/gamecore.cpp
index d2a1652c..af086df2 100644
--- a/src/game/gamecore.cpp
+++ b/src/game/gamecore.cpp
@@ -362,35 +362,37 @@ void CCharacterCore::Move()
 
 	m_Vel.x = m_Vel.x*RampValue;
 
-	vec2 NewPos = m_Pos;

+	vec2 NewPos = m_Pos;
 	m_pCollision->MoveBox(&NewPos, &m_Vel, vec2(28.0f, 28.0f), 0);
 
 	m_Vel.x = m_Vel.x*(1.0f/RampValue);
 
 	if(m_pWorld && m_pWorld->m_Tuning.m_PlayerCollision)
 	{
-		// check player collision

-		float Distance = distance(m_Pos, NewPos);

-		int End = Distance+1;

-		for(int i = 0; i < End; i++)

-		{

-			float a = i/Distance;

-			vec2 Pos = mix(m_Pos, NewPos, a);

-			for(int p = 0; p < MAX_CLIENTS; p++)

-			{

-				CCharacterCore *pCharCore = m_pWorld->m_apCharacters[p];

-				if(!pCharCore || pCharCore == this)

-					continue;

-				float D = distance(Pos, pCharCore->m_Pos);

-				if(D < 28.0f*1.25f && D > 0.0f)

-				{

-					if(a > 0.0f)

-						m_Pos = Pos;

-					else

-						m_Pos = NewPos;

-					return;

-				}

-			}

+		// check player collision
+		float Distance = distance(m_Pos, NewPos);
+		int End = Distance+1;
+		vec2 LastPos = m_Pos;
+		for(int i = 0; i < End; i++)
+		{
+			float a = i/Distance;
+			vec2 Pos = mix(m_Pos, NewPos, a);
+			for(int p = 0; p < MAX_CLIENTS; p++)
+			{
+				CCharacterCore *pCharCore = m_pWorld->m_apCharacters[p];
+				if(!pCharCore || pCharCore == this)
+					continue;
+				float D = distance(Pos, pCharCore->m_Pos);
+				if(D < 28.0f && D > 0.0f)
+				{
+					if(a > 0.0f)
+						m_Pos = LastPos;
+					else if(distance(NewPos, pCharCore->m_Pos) > D)
+						m_Pos = NewPos;
+					return;
+				}
+			}
+			LastPos = Pos;
 		}
 	}
 
diff --git a/src/game/mapitems.h b/src/game/mapitems.h
index d99d6724..fb66e12d 100644
--- a/src/game/mapitems.h
+++ b/src/game/mapitems.h
@@ -53,6 +53,7 @@ enum
 	TILEFLAG_ROTATE=8,
 
 	LAYERFLAG_DETAIL=1,
+	TILESLAYERFLAG_GAME=1,
 
 	ENTITY_OFFSET=255-16*4,
 };
@@ -114,13 +115,15 @@ struct CMapItemGroup_v1
 
 struct CMapItemGroup : public CMapItemGroup_v1
 {
-	enum { CURRENT_VERSION=2 };
+	enum { CURRENT_VERSION=3 };
 
 	int m_UseClipping;
 	int m_ClipX;
 	int m_ClipY;
 	int m_ClipW;
 	int m_ClipH;
+
+	int m_aName[3];
 } ;
 
 struct CMapItemLayer
@@ -145,6 +148,8 @@ struct CMapItemLayerTilemap
 
 	int m_Image;
 	int m_Data;
+
+	int m_aName[3];
 } ;
 
 struct CMapItemLayerQuads
@@ -155,6 +160,8 @@ struct CMapItemLayerQuads
 	int m_NumQuads;
 	int m_Data;
 	int m_Image;
+
+	int m_aName[3];
 } ;
 
 struct CMapItemVersion
diff --git a/src/game/server/entities/character.cpp b/src/game/server/entities/character.cpp
index 899557f2..d7fd74a8 100644
--- a/src/game/server/entities/character.cpp
+++ b/src/game/server/entities/character.cpp
@@ -196,7 +196,7 @@ void CCharacter::HandleNinja()
 				if(m_NumObjectsHit < 10)
 					m_apHitObjects[m_NumObjectsHit++] = aEnts[i];
 
-				aEnts[i]->TakeDamage(vec2(0, 10.0f), g_pData->m_Weapons.m_Ninja.m_pBase->m_Damage, m_pPlayer->GetCID(), WEAPON_NINJA);
+				aEnts[i]->TakeDamage(vec2(0, -10.0f), g_pData->m_Weapons.m_Ninja.m_pBase->m_Damage, m_pPlayer->GetCID(), WEAPON_NINJA);
 			}
 		}
 
diff --git a/src/game/server/gamecontext.cpp b/src/game/server/gamecontext.cpp
index af3c672d..0865cf08 100644
--- a/src/game/server/gamecontext.cpp
+++ b/src/game/server/gamecontext.cpp
@@ -1427,6 +1427,8 @@ void CGameContext::ConForceVote(IConsole::IResult *pResult, void *pUserData)
 			return;
 		}
 
+		str_format(aBuf, sizeof(aBuf), "admin moved '%s' to spectator (%s)", pSelf->Server()->ClientName(SpectateID), pReason);
+		pSelf->SendChatTarget(-1, aBuf);
 		str_format(aBuf, sizeof(aBuf), "set_team %d -1 %d", SpectateID, g_Config.m_SvVoteSpectateRejoindelay);
 		pSelf->Console()->ExecuteLine(aBuf);
 	}
@@ -1453,6 +1455,8 @@ void CGameContext::ConVote(IConsole::IResult *pResult, void *pUserData)
 	else if(str_comp_nocase(pResult->GetString(0), "no") == 0)
 		pSelf->m_VoteEnforce = CGameContext::VOTE_ENFORCE_NO;
 	char aBuf[256];
+	str_format(aBuf, sizeof(aBuf), "admin forced vote %s", pResult->GetString(0));
+	pSelf->SendChatTarget(-1, aBuf);
 	str_format(aBuf, sizeof(aBuf), "forcing vote %s", pResult->GetString(0));
 	pSelf->Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "server", aBuf);
 }
@@ -1476,22 +1480,22 @@ void CGameContext::OnConsoleInit()
 	m_pServer = Kernel()->RequestInterface<IServer>();
 	m_pConsole = Kernel()->RequestInterface<IConsole>();
 
-	Console()->Register("tune", "si", CFGFLAG_SERVER, ConTuneParam, this, "");
-	Console()->Register("tune_reset", "", CFGFLAG_SERVER, ConTuneReset, this, "");
-	Console()->Register("tune_dump", "", CFGFLAG_SERVER, ConTuneDump, this, "");
-
-	Console()->Register("change_map", "?r", CFGFLAG_SERVER|CFGFLAG_STORE, ConChangeMap, this, "");
-	Console()->Register("restart", "?i", CFGFLAG_SERVER|CFGFLAG_STORE, ConRestart, this, "");
-	Console()->Register("broadcast", "r", CFGFLAG_SERVER, ConBroadcast, this, "");
-	Console()->Register("say", "r", CFGFLAG_SERVER, ConSay, this, "");
-	Console()->Register("set_team", "ii?i", CFGFLAG_SERVER, ConSetTeam, this, "");
-	Console()->Register("set_team_all", "i", CFGFLAG_SERVER, ConSetTeamAll, this, "");
-
-	Console()->Register("add_vote", "sr", CFGFLAG_SERVER, ConAddVote, this, "");
-	Console()->Register("remove_vote", "s", CFGFLAG_SERVER, ConRemoveVote, this, "");
-	Console()->Register("force_vote", "ss?r", CFGFLAG_SERVER, ConForceVote, this, "");
-	Console()->Register("clear_votes", "", CFGFLAG_SERVER, ConClearVotes, this, "");
-	Console()->Register("vote", "r", CFGFLAG_SERVER, ConVote, this, "");
+	Console()->Register("tune", "si", CFGFLAG_SERVER, ConTuneParam, this, "Tune variable to value");
+	Console()->Register("tune_reset", "", CFGFLAG_SERVER, ConTuneReset, this, "Reset tuning");
+	Console()->Register("tune_dump", "", CFGFLAG_SERVER, ConTuneDump, this, "Dump tuning");
+
+	Console()->Register("change_map", "?r", CFGFLAG_SERVER|CFGFLAG_STORE, ConChangeMap, this, "Change map");
+	Console()->Register("restart", "?i", CFGFLAG_SERVER|CFGFLAG_STORE, ConRestart, this, "Restart in x seconds");
+	Console()->Register("broadcast", "r", CFGFLAG_SERVER, ConBroadcast, this, "Broadcast message");
+	Console()->Register("say", "r", CFGFLAG_SERVER, ConSay, this, "Say in chat");
+	Console()->Register("set_team", "ii?i", CFGFLAG_SERVER, ConSetTeam, this, "Set team of player to team");
+	Console()->Register("set_team_all", "i", CFGFLAG_SERVER, ConSetTeamAll, this, "Set team of all players to team");
+
+	Console()->Register("add_vote", "sr", CFGFLAG_SERVER, ConAddVote, this, "Add a voting option");
+	Console()->Register("remove_vote", "s", CFGFLAG_SERVER, ConRemoveVote, this, "remove a voting option");
+	Console()->Register("force_vote", "ss?r", CFGFLAG_SERVER, ConForceVote, this, "Force a voting option");
+	Console()->Register("clear_votes", "", CFGFLAG_SERVER, ConClearVotes, this, "Clears the voting options");
+	Console()->Register("vote", "r", CFGFLAG_SERVER, ConVote, this, "Force a vote to yes/no");
 
 	Console()->Chain("sv_motd", ConchainSpecialMotdupdate, this);
 }
diff --git a/src/game/server/gamecontroller.cpp b/src/game/server/gamecontroller.cpp
index 56407a77..eb9dc9b5 100644
--- a/src/game/server/gamecontroller.cpp
+++ b/src/game/server/gamecontroller.cpp
@@ -227,6 +227,7 @@ void IGameController::StartRound()
 	m_aTeamscore[TEAM_RED] = 0;
 	m_aTeamscore[TEAM_BLUE] = 0;
 	m_ForceBalanced = false;
+	Server()->DemoRecorder_HandleAutoStart();
 	char aBuf[256];
 	str_format(aBuf, sizeof(aBuf), "start round type='%s' teamplay='%d'", m_pGameType, m_GameFlags&GAMEFLAG_TEAMS);
 	GameServer()->Console()->Print(IConsole::OUTPUT_LEVEL_DEBUG, "game", aBuf);
@@ -672,7 +673,7 @@ bool IGameController::CanChangeTeam(CPlayer *pPlayer, int JoinTeam)
 
 void IGameController::DoWincheck()
 {
-	if(m_GameOverTick == -1 && !m_Warmup)
+	if(m_GameOverTick == -1 && !m_Warmup && !GameServer()->m_World.m_ResetRequested)
 	{
 		if(IsTeamplay())
 		{
diff --git a/src/game/server/player.cpp b/src/game/server/player.cpp
index 7bac6454..cccff50f 100644
--- a/src/game/server/player.cpp
+++ b/src/game/server/player.cpp
@@ -112,6 +112,9 @@ void CPlayer::Tick()
 		}
 	}
 
+	if(!m_pCharacter && m_Team == TEAM_SPECTATORS && m_SpectatorID == SPEC_FREEVIEW)
+		m_ViewPos -= vec2(clamp(m_ViewPos.x-m_LatestActivity.m_TargetX, -500.0f, 500.0f), clamp(m_ViewPos.y-m_LatestActivity.m_TargetY, -400.0f, 400.0f));
+
 	if(!m_pCharacter && m_DieTick+Server()->TickSpeed()*3 <= Server()->Tick())
 		m_Spawning = true;
 
@@ -259,9 +262,6 @@ void CPlayer::OnDirectInput(CNetObj_PlayerInput *NewInput)
 	if(!m_pCharacter && m_Team != TEAM_SPECTATORS && (NewInput->m_Fire&1))
 		m_Spawning = true;
 
-	if(!m_pCharacter && m_Team == TEAM_SPECTATORS && m_SpectatorID == SPEC_FREEVIEW)
-		m_ViewPos = vec2(NewInput->m_TargetX, NewInput->m_TargetY);
-
 	// check for activity
 	if(NewInput->m_Direction || m_LatestActivity.m_TargetX != NewInput->m_TargetX ||
 		m_LatestActivity.m_TargetY != NewInput->m_TargetY || NewInput->m_Jump ||
diff --git a/src/game/variables.h b/src/game/variables.h
index 28d8ceea..c913a46b 100644
--- a/src/game/variables.h
+++ b/src/game/variables.h
@@ -45,6 +45,7 @@ MACRO_CONFIG_INT(UiPage, ui_page, 5, 0, 10, CFGFLAG_CLIENT|CFGFLAG_SAVE, "Interf
 MACRO_CONFIG_INT(UiToolboxPage, ui_toolbox_page, 0, 0, 2, CFGFLAG_CLIENT|CFGFLAG_SAVE, "Toolbox page")
 MACRO_CONFIG_STR(UiServerAddress, ui_server_address, 64, "localhost:8303", CFGFLAG_CLIENT|CFGFLAG_SAVE, "Interface server address")
 MACRO_CONFIG_INT(UiScale, ui_scale, 100, 50, 150, CFGFLAG_CLIENT|CFGFLAG_SAVE, "Interface scale")
+MACRO_CONFIG_INT(UiMousesens, ui_mousesens, 100, 5, 100000, CFGFLAG_SAVE|CFGFLAG_CLIENT, "Mouse sensitivity for menus/editor")
 
 MACRO_CONFIG_INT(UiColorHue, ui_color_hue, 160, 0, 255, CFGFLAG_CLIENT|CFGFLAG_SAVE, "Interface color hue")
 MACRO_CONFIG_INT(UiColorSat, ui_color_sat, 70, 0, 255, CFGFLAG_CLIENT|CFGFLAG_SAVE, "Interface color saturation")
@@ -95,4 +96,4 @@ MACRO_CONFIG_INT(SvAllowJoin, sv_allow_join, 2, 0, 2, CFGFLAG_SERVER, "Allow new
 //0 - Wait for next round; 1 = Allowed to join; 2 = Will join when person with the most kills die
 MACRO_CONFIG_INT(SvColorIndicator, sv_color_indicator, 1, 0, 1, CFGFLAG_SERVER, "Color tees apropriate to the number of currently catched players")
 MACRO_CONFIG_INT(SvBonus, sv_bonus, 0, 0, 10000, CFGFLAG_SERVER, "Give the last player extra points")
-MACRO_CONFIG_INT(SvFollowCatcher, sv_follow_catcher, 1, 0, 1, CFGFLAG_SERVER, "If a victim should follow his catcher")
\ No newline at end of file
+MACRO_CONFIG_INT(SvFollowCatcher, sv_follow_catcher, 1, 0, 1, CFGFLAG_SERVER, "If a victim should follow his catcher")
diff --git a/src/game/version.h b/src/game/version.h
index c7f04b75..76b6d4ab 100644
--- a/src/game/version.h
+++ b/src/game/version.h
@@ -3,6 +3,6 @@
 #ifndef GAME_VERSION_H
 #define GAME_VERSION_H
 #include "generated/nethash.cpp"
-#define GAME_VERSION "0.6 trunk"
+#define GAME_VERSION "0.6.1"
 #define GAME_NETVERSION "0.6 " GAME_NETVERSION_HASH
 #endif
diff --git a/src/tools/dilate.cpp b/src/tools/dilate.cpp
index ef862270..eb770a90 100644
--- a/src/tools/dilate.cpp
+++ b/src/tools/dilate.cpp
@@ -48,18 +48,18 @@ static void CopyAlpha(int w, int h, CPixel *pSrc, CPixel *pDest)
 			pDest[m].a = pSrc[m].a;
 }
 
-int main(int argc, char **argv)
+int DilateFile(const char *pFileName)
 {
 	png_t Png;
 	CPixel *pBuffer[3] = {0,0,0};
 
 	png_init(0, 0);
-	png_open_file(&Png, argv[1]);
+	png_open_file(&Png, pFileName);
 
 	if(Png.color_type != PNG_TRUECOLOR_ALPHA)
 	{
-		dbg_msg("dilate", "not an RGBA image");
-		return -1;
+		dbg_msg("dilate", "%s: not an RGBA image", pFileName);
+		return 1;
 	}
 
 	pBuffer[0] = (CPixel*)mem_alloc(Png.width*Png.height*sizeof(CPixel), 1);
@@ -81,9 +81,23 @@ int main(int argc, char **argv)
 	CopyAlpha(w, h, pBuffer[0], pBuffer[1]);
 
 	// save here
-	png_open_file_write(&Png, argv[1]);
+	png_open_file_write(&Png, pFileName);
 	png_set_data(&Png, w, h, 8, PNG_TRUECOLOR_ALPHA, (unsigned char *)pBuffer[1]);
 	png_close_file(&Png);
 
 	return 0;
 }
+
+int main(int argc, const char **argv)
+{
+	dbg_logger_stdout();
+	if(argc == 1)
+	{
+		dbg_msg("Usage", "%s FILE1 [ FILE2... ]", argv[0]);
+		return -1;
+	}
+	
+	for(int i = 1; i < argc; i++)
+		DilateFile(argv[i]);
+	return 0;
+}
diff --git a/src/tools/tileset_borderfix.cpp b/src/tools/tileset_borderfix.cpp
index 6fb32d4b..0facb9a3 100644
--- a/src/tools/tileset_borderfix.cpp
+++ b/src/tools/tileset_borderfix.cpp
@@ -51,18 +51,18 @@ static void TilesetBorderfix(int w, int h, CPixel *pSrc, CPixel *pDest)
 }
 
 
-int main(int argc, char **argv)
+int FixFile(const char *pFileName)
 {
 	png_t Png;
 	CPixel *pBuffer[2] = {0,0};
 
 	png_init(0, 0);
-	png_open_file(&Png, argv[1]);
+	png_open_file(&Png, pFileName);
 
 	if(Png.color_type != PNG_TRUECOLOR_ALPHA)
 	{
-		dbg_msg("dilate", "not an RGBA image");
-		return -1;
+		dbg_msg("tileset_borderfix", "%s: not an RGBA image", pFileName);
+		return 1;
 	}
 
 	int w = Png.width;
@@ -76,9 +76,23 @@ int main(int argc, char **argv)
 	TilesetBorderfix(w, h, pBuffer[0], pBuffer[1]);
 
 	// save here
-	png_open_file_write(&Png, argv[1]);
+	png_open_file_write(&Png, pFileName);
 	png_set_data(&Png, w, h, 8, PNG_TRUECOLOR_ALPHA, (unsigned char *)pBuffer[1]);
 	png_close_file(&Png);
 
 	return 0;
 }
+
+int main(int argc, const char **argv)
+{
+	dbg_logger_stdout();
+	if(argc == 1)
+	{
+		dbg_msg("Usage", "%s FILE1 [ FILE2... ]", argv[0]);
+		return -1;
+	}
+
+	for(int i = 1; i < argc; i++)
+		FixFile(argv[i]);
+	return 0;
+}