diff --git a/data/languages/bosnian.txt b/data/languages/bosnian.txt
new file mode 100644
index 0000000..b9bee26
--- /dev/null
+++ b/data/languages/bosnian.txt
@@ -0,0 +1,661 @@
+
+##### translated strings #####
+
+%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
+== Preostalo: %i min.
+
+%i minutes left
+== Preostalo: %i min.
+
+%i second left
+== Preostalo: %i sek.
+
+%i seconds left
+== Preostalo: %i sek.
+
+Abort
+== Prekini
+
+Address
+== Adresa
+
+All
+== Svi
+
+Alpha
+== Provid.
+
+Always show name plates
+== Uvijek prikaži imena igrača
+
+Are you sure that you want to delete the demo?
+== Jeste li sigurni da želite obrisati demo-snimak?
+
+Are you sure that you want to quit?
+== Jeste li sigurni da želite izići?
+
+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 provjerite postavke i podesite ih prema Vašem ukusu prije nego se konektujete na server.
+
+Automatically record demos
+== Automatski demo-snimci
+
+Automatically take game over screenshot
+== Automatski screenshot po završetku igre
+
+Blue team
+== Plavi tim
+
+Blue team wins!
+== Plavi tim je pobijedio!
+
+Body
+== Tijelo
+
+Call vote
+== Glasanje
+
+Chat
+== Chat
+
+Close
+== Zatvori
+
+Compatible version
+== Kompatibilna verzija
+
+Connect
+== Konektuj
+
+Connecting to
+== Konektujem na
+
+Connection Problems...
+== Problemi sa konekcijom...
+
+Console
+== Konzola
+
+Controls
+== Kontrole
+
+Current
+== Current
+
+Current version: %s
+== Trenutna verzija: %s
+
+Custom colors
+== Vlastite boje
+
+Delete
+== Obriši
+
+Delete demo
+== Brisanje demo-snimka
+
+Demos
+== Demo
+
+Disconnect
+== Diskonektuj
+
+Disconnected
+== Diskonektovan
+
+Display Modes
+== Rezolucija i način prikaza
+
+Downloading map
+== Preuzimam mapu
+
+Draw!
+== Neriješeno!
+
+Dynamic Camera
+== Dinamička kamera
+
+Emoticon
+== Emoticon
+
+Enter
+== Započni
+
+Error
+== Greška
+
+Error loading demo
+== Greška prilikom učitavanja demo-snimka
+
+FSAA samples
+== FSAA samples
+
+Favorite
+== Omiljeni
+
+Favorites
+== Omiljeni
+
+Feet
+== Stopala
+
+Filter
+== Filter
+
+Fire
+== Pucanje
+
+Folder
+== Direktorij
+
+Force vote
+== Obavezno glasanje
+
+Fullscreen
+== Čitav ekran
+
+Game
+== Igra
+
+Game info
+== O igri
+
+Game over
+== Igra je završena
+
+Game type
+== Tip igre
+
+Game types:
+== Tipovi igre:
+
+General
+== Opće
+
+Graphics
+== Grafika
+
+Grenade
+== Granate
+
+Hammer
+== Čekić
+
+Has people playing
+== Server nije prazan
+
+High Detail
+== Visoki detalji
+
+Hook
+== Lanac
+
+Host address
+== Adresa servera
+
+Hue
+== Nijans.
+
+Info
+== Info
+
+Internet
+== Internet
+
+Invalid Demo
+== Neispravan demo-snimak
+
+Join blue
+== U plavi tim
+
+Join game
+== Uključi se u igru
+
+Join red
+== U crveni tim
+
+Jump
+== Skok
+
+LAN
+== LAN
+
+Language
+== Jezik
+
+Lht.
+== Svjetl.
+
+Loading
+== Učitavam
+
+MOTD
+== Vijest dana
+
+Map
+== Mapa
+
+Max Screenshots
+== Maksimalan broj screenshot-a
+
+Max demos
+== Maximalan broj demo-snimaka
+
+Maximum ping:
+== Maksimalan ping:
+
+Miscellaneous
+== Razno
+
+Mouse sens.
+== Osjetljivost miša
+
+Move left
+== Nalijevo
+
+Move right
+== Nadesno
+
+Movement
+== Kretanje
+
+Mute when not active
+== Bez zvuka prilikom neaktivnosti
+
+Name
+== Ime
+
+News
+== Novosti
+
+Next weapon
+== Sljedeće oružje
+
+Nickname
+== Nadimak
+
+No
+== Ne
+
+No password
+== Bez lozinke
+
+No servers found
+== Nije pronađen nijedan server
+
+No servers match your filter criteria
+== Nijedan server ne odgovara zadatom kriteriju
+
+Ok
+== OK
+
+Open
+== Otvori
+
+Parent Folder
+== Prethodni direktorij
+
+Password
+== Lozinka
+
+Password incorrect
+== Pogrešna lozinka
+
+Ping
+== Ping
+
+Pistol
+== Pištolj
+
+Play
+== Pogledaj
+
+Player
+== Igrač
+
+Players
+== Igrači
+
+Please balance teams!
+== Molim uravnotežite timove!
+
+Prev. weapon
+== Prethodno oružje
+
+Quality Textures
+== Visokokvalitetne teksture
+
+Quick search:
+== Brza pretraga:
+
+Quit
+== Izlaz
+
+Record demo
+== Snimi demo
+
+Red team
+== Crveni tim
+
+Red team wins!
+== Crveni tim je pobijedio!
+
+Refresh
+== Osvježi
+
+Refreshing master servers
+== Osvježavam glavne servere
+
+Remote console
+== Udaljena konzola
+
+Reset filter
+== Poništi filter
+
+Reset to defaults
+== Vrati na početne postavke
+
+Rifle
+== Laser
+
+Round
+== Runda
+
+Sample rate
+== Frekvencija
+
+Sat.
+== Zasić.
+
+Score
+== Rezultat
+
+Score board
+== Bodovi
+
+Score limit
+== Max. bodova
+
+Scoreboard
+== Bodovi
+
+Screenshot
+== Screenshot
+
+Server details
+== Podaci o serveru
+
+Server info
+== O Serveru
+
+Server not full
+== Server nije pun
+
+Settings
+== Postavke
+
+Shotgun
+== Pumparica
+
+Show chat
+== Prikaži chat
+
+Show name plates
+== Prikaži imena igrača
+
+Show only supported
+== Prikaži samo podržane
+
+Skins
+== Izgled
+
+Sound
+== Zvuk
+
+Sound volume
+== Jačina zvuka
+
+Spectate
+== Posmatraj
+
+Spectators
+== Posmatrači
+
+Standard gametype
+== Standardni tip igre
+
+Standard map
+== Standardna mapa
+
+Sudden Death
+== Iznenadna smrt
+
+Switch weapon on pickup
+== Aktiviraj novo oružje prilikom uzimanja
+
+Team
+== Tim
+
+Team chat
+== Timski chat
+
+Teeworlds %s is out! Download it at www.teeworlds.com!
+== Teeworld %s je objavljen! Preuzmi ga na www.teeworlds.com!
+
+Texture Compression
+== Kompresija tekstura
+
+The server is running a non-standard tuning on a pure game type.
+== Server sadrži nestandardne postavke.
+
+Time limit
+== Max. vremena
+
+Time limit: %d min
+== Max. vremena: %d min.
+
+Try again
+== Pokušaj ponovo
+
+Type
+== Tip
+
+UI Color
+== Boja menija
+
+Use sounds
+== Aktiviraj zvuk
+
+V-Sync
+== V-Sync
+
+Version
+== Verzija
+
+Vote no
+== Ne
+
+Vote yes
+== Da
+
+Voting
+== Glasanje
+
+Warmup
+== Zagrijavanje
+
+Weapon
+== Oružje
+
+Welcome to Teeworlds
+== Dobrodošli u Teeworlds
+
+Yes
+== Da
+
+You must restart the game for all settings to take effect.
+== Morate ponovo pokrenuti igru da bi sve postavke bile primijenjene.
+
+Your skin
+== Vaš izgled
+
+##### needs translation #####
+
+%d Bytes
+==
+
+%s wins!
+==
+
+-Page %d-
+==
+
+Add
+==
+
+Add Friend
+==
+
+Are you sure that you want to remove the player from your friends list?
+==
+
+Change settings
+==
+
+Clan
+==
+
+Client
+==
+
+Count players only
+==
+
+Country
+==
+
+Crc:
+==
+
+Created:
+==
+
+Demo details
+==
+
+Free-View
+==
+
+Friends
+==
+
+Kick player
+==
+
+Length:
+==
+
+Map:
+==
+
+Move player to spectators
+==
+
+Name plates size
+==
+
+Netversion:
+==
+
+New name:
+==
+
+Player options
+==
+
+Quit anyway?
+==
+
+REC %3d:%02d
+==
+
+Reason:
+==
+
+Remove
+==
+
+Remove friend
+==
+
+Rename
+==
+
+Rename demo
+==
+
+Server address:
+==
+
+Server filter
+==
+
+Show friends
+==
+
+Show ingame HUD
+==
+
+Size:
+==
+
+Sound error
+==
+
+Spectator mode
+==
+
+Stop record
+==
+
+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.
+==
+
+Type:
+==
+
+Unable to delete the demo
+==
+
+Unable to rename the demo
+==
+
+Use team colors for name plates
+==
+
+Version:
+==
+
+Vote command:
+==
+
+Vote description:
+==
+
+no limit
+==
+
+##### old translations #####
+
diff --git a/data/languages/index.txt b/data/languages/index.txt
index a6616b0..e1dc0d4 100644
--- a/data/languages/index.txt
+++ b/data/languages/index.txt
@@ -1,8 +1,8 @@
##### language indices #####
-#bosnian
-#== Bosanski
+bosnian
+== Bosanski
bulgarian
== Български
@@ -22,23 +22,23 @@ french
german
== Deutsch
-#italian
-#== Italiano
+italian
+== Italiano
-#polish
-#== Polski
+polish
+== Polski
-#portuguese
-#== Português
+portuguese
+== Português
-#romanian
-#== Română
+romanian
+== Română
-#russian
-#== Русский
+russian
+== Русский
-#serbian
-#== Srpski
+serbian
+== Srpski
slovak
== Slovensky
@@ -49,5 +49,5 @@ spanish
swedish
== Svenska
-#ukrainian
-#== Українська
+ukrainian
+== Українська
diff --git a/data/languages/italian.txt b/data/languages/italian.txt
new file mode 100644
index 0000000..8798c0b
--- /dev/null
+++ b/data/languages/italian.txt
@@ -0,0 +1,661 @@
+
+##### translated strings #####
+
+%d of %d servers, %d players
+== %d di %d server, %d giocatori
+
+%d%% loaded
+== %d%% caricati
+
+%ds left
+== %ds ancora
+
+%i minute left
+== %i minuto ancora
+
+%i minutes left
+== %i minuti ancora
+
+%i second left
+== %i secondo ancora
+
+%i seconds left
+== %i secondi ancora
+
+Abort
+== Annulla
+
+Address
+== Indirizzo
+
+All
+== Tutti
+
+Alpha
+== Alpha
+
+Always show name plates
+== Mostra sempre etichette dei nomi
+
+Are you sure that you want to delete the demo?
+== Sicuro di voler cancellare questa registrazione?
+
+Are you sure that you want to quit?
+== Sicuro di voler uscire?
+
+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, ti preghiamo di inserire il tuo nickname. E' consigliato aggiustare le impostazioni in base alle proprie preferenze prima di entrare in un server.
+
+Automatically record demos
+== Registra demo automaticamente
+
+Automatically take game over screenshot
+== Foto automatica a fine partita
+
+Blue team
+== Squadra Blu
+
+Blue team wins!
+== La squadra blu ha vinto!
+
+Body
+== Corpo
+
+Call vote
+== Inizia voto
+
+Chat
+== Chat
+
+Close
+== Chiudi
+
+Compatible version
+== Versione compatibile
+
+Connect
+== Connetti
+
+Connecting to
+== Connessione a
+
+Connection Problems...
+== Connessione Persa...
+
+Console
+== Console
+
+Controls
+== Controlli
+
+Current
+== Attuale
+
+Current version: %s
+== Versione attuale: %s
+
+Custom colors
+== Colori personalizzati
+
+Delete
+== Cancella
+
+Delete demo
+== Cancella demo
+
+Demos
+== Demo
+
+Disconnect
+== Disconnetti
+
+Disconnected
+== Disconnesso
+
+Display Modes
+== Tipo di visualizzazione
+
+Downloading map
+== Scaricando la mappa
+
+Draw!
+== Pareggio!
+
+Dynamic Camera
+== Visuale dinamica
+
+Emoticon
+== Emozioni
+
+Enter
+== Entra
+
+Error
+== Errore
+
+Error loading demo
+== Impossibile caricare la demo
+
+FSAA samples
+== Esempi FSAA
+
+Favorite
+== Preferito
+
+Favorites
+== Preferiti
+
+Feet
+== Piedi
+
+Filter
+== Filtro
+
+Fire
+== Fuoco
+
+Folder
+== Cartella
+
+Force vote
+== Forza voto
+
+Fullscreen
+== Schermo intero
+
+Game
+== Gioco
+
+Game info
+== Dettagli gioco
+
+Game over
+== Game over
+
+Game type
+== Tipo di gioco
+
+Game types:
+== Tipi di gioco:
+
+General
+== Generale
+
+Graphics
+== Grafica
+
+Grenade
+== Granata
+
+Hammer
+== Martello
+
+Has people playing
+== Ha gente in gioco
+
+High Detail
+== Molti dettagli
+
+Hook
+== Rampino
+
+Host address
+== Indirizzo host
+
+Hue
+== Col.
+
+Info
+== Info
+
+Internet
+== Internet
+
+Invalid Demo
+== Demo non valida
+
+Join blue
+== Entra blu
+
+Join game
+== Entra
+
+Join red
+== Entra rosso
+
+Jump
+== Salta
+
+LAN
+== LAN
+
+Language
+== Lingua
+
+Lht.
+== Lum.
+
+Loading
+== Caricamento
+
+MOTD
+== MDG
+
+Map
+== Mappa
+
+Maximum ping:
+== Ping massimo:
+
+Miscellaneous
+== Altro
+
+Mouse sens.
+== Sensibilità
+
+Move left
+== Muovi a sinistra
+
+Move right
+== Muovi a destra
+
+Movement
+== Movimento
+
+Mute when not active
+== Muto quando inattivo
+
+Name
+== Nome
+
+Name plates size
+== Dimensione etichetta
+
+News
+== Notizie
+
+Next weapon
+== Successiva
+
+Nickname
+== Nickname
+
+No
+== No
+
+No password
+== Senza password
+
+No servers found
+== Nessun server trovato
+
+No servers match your filter criteria
+== Nessun server corrisponde ai filtri di ricerca
+
+Ok
+== Ok
+
+Open
+== Apri
+
+Parent Folder
+== Indietro
+
+Password
+== Password
+
+Password incorrect
+== Password errata
+
+Ping
+== Ping
+
+Pistol
+== Pistola
+
+Play
+== Guarda
+
+Player
+== Giocatore
+
+Players
+== Giocatori
+
+Please balance teams!
+== Squadre sbilanciate!
+
+Prev. weapon
+== Precedente
+
+Quality Textures
+== Textures di qualità
+
+Quick search:
+== Ricerca rapida:
+
+Quit
+== Esci
+
+Reason:
+== Motivo:
+
+Record demo
+== Registra demo
+
+Red team
+== Squadra rossa
+
+Red team wins!
+== La squadra rossa ha vinto!
+
+Refresh
+== Aggiorna
+
+Refreshing master servers
+== Aggiornando la lista server
+
+Remote console
+== Console remota
+
+Reset filter
+== Annulla filtri
+
+Reset to defaults
+== Reimposta
+
+Rifle
+== Laser
+
+Round
+== Turno
+
+Sample rate
+== Frequenza
+
+Sat.
+== Sat.
+
+Score
+== Punti
+
+Score board
+== Scoreboard
+
+Score limit
+== Punteggio massimo
+
+Scoreboard
+== Scoreboard
+
+Screenshot
+== Screenshot
+
+Server details
+== Dettagli del server
+
+Server info
+== Dettagli
+
+Server not full
+== Server non pieno
+
+Settings
+== Impostazioni
+
+Shotgun
+== Fucile
+
+Show chat
+== Mostra Chat
+
+Show name plates
+== Mostra etichetta nomi
+
+Show only supported
+== Mostra solo supportati
+
+Skins
+== Skins
+
+Sound
+== Suono
+
+Sound volume
+== Volume
+
+Spectate
+== Osserva
+
+Spectators
+== Spettatori
+
+Standard gametype
+== Tipo di gioco classico
+
+Standard map
+== Mappa classica
+
+Stop record
+== Termina reg.
+
+Switch weapon on pickup
+== Cambia arma alla raccolta
+
+Team
+== Squadra
+
+Team chat
+== Chat di squadra
+
+Teeworlds %s is out! Download it at www.teeworlds.com!
+== E' uscito Teeworlds %s! Scaricalo da www.teeworlds.com !
+
+Texture Compression
+== 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 sta eseguendo un tuning non-standard su un tipo di gioco classico.
+
+Time limit
+== Limite di tempo
+
+Time limit: %d min
+== Tempo limite %d min
+
+Try again
+== Ritenta
+
+Type
+== Tipo
+
+UI Color
+== Colore del menu
+
+Unable to delete the demo
+== Impossibile eliminare la registrazione
+
+Use sounds
+== Usa suoni
+
+V-Sync
+== V-Sync
+
+Version
+== Versione
+
+Vote no
+== Vota no
+
+Vote yes
+== Vota si
+
+Voting
+== Votazione
+
+Weapon
+== Attiva arma
+
+Welcome to Teeworlds
+== Benvenuto su Teeworlds!
+
+Yes
+== Si
+
+You must restart the game for all settings to take effect.
+== E' necessario riavviare il gioco per rendere effettive le modifiche.
+
+Your skin
+== La tua Skin
+
+no limit
+== senza limite
+
+##### needs translation #####
+
+%d Bytes
+==
+
+%s wins!
+==
+
+-Page %d-
+==
+
+Add
+==
+
+Add Friend
+==
+
+Are you sure that you want to remove the player from your friends list?
+==
+
+Change settings
+==
+
+Clan
+==
+
+Client
+==
+
+Count players only
+==
+
+Country
+==
+
+Crc:
+==
+
+Created:
+==
+
+Demo details
+==
+
+Free-View
+==
+
+Friends
+==
+
+Kick player
+==
+
+Length:
+==
+
+Map:
+==
+
+Max Screenshots
+==
+
+Max demos
+==
+
+Move player to spectators
+==
+
+Netversion:
+==
+
+New name:
+==
+
+Player options
+==
+
+Quit anyway?
+==
+
+REC %3d:%02d
+==
+
+Remove
+==
+
+Remove friend
+==
+
+Rename
+==
+
+Rename demo
+==
+
+Server address:
+==
+
+Server filter
+==
+
+Show friends
+==
+
+Show ingame HUD
+==
+
+Size:
+==
+
+Sound error
+==
+
+Spectator mode
+==
+
+Sudden Death
+==
+
+There's an unsaved map in the editor, you might want to save it before you quit the game.
+==
+
+Type:
+==
+
+Unable to rename the demo
+==
+
+Use team colors for name plates
+==
+
+Version:
+==
+
+Vote command:
+==
+
+Vote description:
+==
+
+Warmup
+==
+
+##### old translations #####
+
diff --git a/data/languages/polish.txt b/data/languages/polish.txt
new file mode 100644
index 0000000..857650f
--- /dev/null
+++ b/data/languages/polish.txt
@@ -0,0 +1,661 @@
+
+##### translated strings #####
+
+%d of %d servers, %d players
+== %d z %d serwerów, %d graczy
+
+%ds left
+== Jeszcze %d
+
+Abort
+== Anuluj
+
+Address
+== Adres
+
+All
+== Wszyscy
+
+Alpha
+== Alfa
+
+Always show name plates
+== Zawsze pokazuj nicki
+
+Are you sure that you want to quit?
+== Czy na pewno chcesz opuścić grę?
+
+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.
+
+Blue team
+== Drużyna niebieskich
+
+Blue team wins!
+== Drużyna niebieskich wygrała!
+
+Body
+== Ciało
+
+Call vote
+== Głosowanie
+
+Chat
+== Chat
+
+Close
+== Zamknij
+
+Compatible version
+== Kompatybilna wersja
+
+Connect
+== Połącz
+
+Connecting to
+== Łączenie z
+
+Connection Problems...
+== Problemy z połączeniem...
+
+Console
+== Konsola
+
+Controls
+== Sterowanie
+
+Current
+== Aktualnie
+
+Current version: %s
+== Aktualna wersja: %s
+
+Custom colors
+== Własne kolory
+
+Delete
+== Usuń
+
+Demos
+== Dema
+
+Disconnect
+== Rozłącz
+
+Disconnected
+== Rozłączono
+
+Display Modes
+== Tryby wyświetlania
+
+Downloading map
+== Pobieranie mapy
+
+Draw!
+== Remis!
+
+Dynamic Camera
+== Dynamiczna kamera
+
+Emoticon
+== Emotikonka
+
+Enter
+== Wejdź
+
+Error
+== Błąd
+
+Error loading demo
+== Błąd przy ładowaniu demo
+
+FSAA samples
+== próbki FSAA (anti-aliasing)
+
+Favorite
+== Ulubiony
+
+Favorites
+== Ulubione
+
+Feet
+== Stopy
+
+Filter
+== Filtr
+
+Fire
+== Strzał
+
+Force vote
+== Wymuś głosowanie
+
+Fullscreen
+== Pełny ekran
+
+Game
+== Gra
+
+Game info
+== Informacje o grze
+
+Game over
+== Koniec gry
+
+Game type
+== Typ gry
+
+Game types:
+== Typy gier:
+
+General
+== Ogólne
+
+Graphics
+== Grafika
+
+Grenade
+== Granatnik
+
+Hammer
+== Młot
+
+Has people playing
+== Nie pokazuj pustych
+
+High Detail
+== Wysoka jakość obrazu
+
+Hook
+== Hak
+
+Host address
+== Adres serwera
+
+Hue
+== Kolor
+
+Info
+== Info
+
+Internet
+== Internet
+
+Join blue
+== Dołącz do niebieskich
+
+Join game
+== Dołącz
+
+Join red
+== Dołącz do czerwonych
+
+Jump
+== Skok
+
+LAN
+== LAN
+
+Language
+== Język
+
+Lht.
+== Jasn.
+
+Loading
+== Ładowanie
+
+MOTD
+== Wiadomość dnia
+
+Map
+== Mapa
+
+Maximum ping:
+== Maksymalny ping:
+
+Miscellaneous
+== Różne
+
+Mouse sens.
+== Czułość myszy
+
+Move left
+== Lewo
+
+Move right
+== Prawo
+
+Movement
+== Ruch
+
+Mute when not active
+== Wycisz kiedy gra nieaktywna
+
+Name
+== Nick
+
+News
+== News
+
+Next weapon
+== Następna broń
+
+Nickname
+== Nick
+
+No
+== Nie
+
+No password
+== Bez hasła
+
+No servers found
+== Nie znaleziono serwerów
+
+No servers match your filter criteria
+== Nie znaleziono serwerów spełniających twoje kryteria
+
+Ok
+== OK
+
+Open
+== Otwórz
+
+Password
+== Hasło
+
+Password incorrect
+== Błędne hasło
+
+Ping
+== Ping
+
+Pistol
+== Pistolet
+
+Play
+== Start
+
+Player
+== Gracz
+
+Players
+== Gracze
+
+Please balance teams!
+== Konieczne wyrównanie drużyn!
+
+Prev. weapon
+== Poprzednia broń
+
+Quality Textures
+== Szczegółowe tekstury
+
+Quick search:
+== Szybkie wyszukiwanie:
+
+Quit
+== Wyjście
+
+Red team
+== Drużyna czerwonych
+
+Red team wins!
+== Drużyna czerwonych wygrała!
+
+Refresh
+== Odśwież
+
+Refreshing master servers
+== Odświeżanie głównych serwerów
+
+Remote console
+== Zdalna konsola
+
+Reset filter
+== Domyślne filtry
+
+Reset to defaults
+== Przywróć domyślne
+
+Rifle
+== Laser
+
+Round
+== Runda
+
+Sample rate
+== Próbkowanie
+
+Sat.
+== Nasyc.
+
+Score
+== Wynik
+
+Score board
+== Tablica wyników
+
+Score limit
+== Limit punktów
+
+Scoreboard
+== Tablica wyników
+
+Screenshot
+== Screenshot
+
+Server details
+== Szczegóły serwera
+
+Server info
+== Server info
+
+Server not full
+== Nie pokazuj pełnych
+
+Settings
+== Opcje
+
+Shotgun
+== Shotgun
+
+Show chat
+== Pokaż chat
+
+Show name plates
+== Pokaż nicki
+
+Show only supported
+== Pokaż tylko wspierane
+
+Skins
+== Motywy
+
+Sound
+== Dźwięk
+
+Sound volume
+== Głośność
+
+Spectate
+== Obserwuj
+
+Spectators
+== Obserwatorzy
+
+Standard gametype
+== Standardowy typ gry
+
+Standard map
+== Standardowa mapa
+
+Sudden Death
+== Nagła śmierć
+
+Switch weapon on pickup
+== Zmień broń po podniesieniu
+
+Team
+== Drużyna
+
+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!
+
+Texture Compression
+== Kompresja tekstur
+
+The server is running a non-standard tuning on a pure game type.
+== Ten serwer nie korzysta ze standardowych ustawień.
+
+Time limit
+== Limit czasu
+
+Try again
+== Ponów próbę
+
+Type
+== Typ
+
+UI Color
+== Kolor menu
+
+Use sounds
+== Włącz dźwięki
+
+V-Sync
+== V-Sync
+
+Version
+== Wersja
+
+Vote no
+== Nie
+
+Vote yes
+== Tak
+
+Voting
+== Głosowanie
+
+Warmup
+== Rozgrzewka
+
+Weapon
+== Bronie
+
+Welcome to Teeworlds
+== Witaj w Teeworlds
+
+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.
+
+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
+==
+
+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
+==
+
+Player options
+==
+
+Quit anyway?
+==
+
+REC %3d:%02d
+==
+
+Reason:
+==
+
+Record demo
+==
+
+Remove
+==
+
+Remove friend
+==
+
+Rename
+==
+
+Rename demo
+==
+
+Server address:
+==
+
+Server filter
+==
+
+Show friends
+==
+
+Show ingame HUD
+==
+
+Size:
+==
+
+Sound error
+==
+
+Spectator mode
+==
+
+Stop record
+==
+
+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
+==
+
+##### old translations #####
+
diff --git a/data/languages/portuguese.txt b/data/languages/portuguese.txt
new file mode 100644
index 0000000..543ece6
--- /dev/null
+++ b/data/languages/portuguese.txt
@@ -0,0 +1,665 @@
+##### translated strings #####
+
+%d of %d servers, %d players
+== %d de %d servidores, %d jogadores
+
+%ds left
+== faltam %ds
+
+Abort
+== Cancelar
+
+Address
+== Endereço
+
+All
+== Todos
+
+Alpha
+== Alpha
+
+Always show name plates
+== Sempre mostrar apelidos
+
+Are you sure that you want to quit?
+== Você tem certeza que deseja sair?
+
+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, entre com seu apelido abaixo. É
+
+recomendado que você cheque as configurações e então ajuste elas para suas preferências antes de
+
+entrar em um servidor.
+
+Blue team
+== Time azul
+
+Blue team wins!
+== Time azul vence!
+
+Body
+== Corpo
+
+Call vote
+== Votação
+
+Chat
+== Conversa
+
+Close
+== Fechar
+
+Compatible version
+== Versão compatível
+
+Connect
+== Conectar
+
+Connecting to
+== Conectando a
+
+Connection Problems...
+== Problemas de Conexão...
+
+Console
+== Console
+
+Controls
+== Controles
+
+Current
+== Atualmente
+
+Current version: %s
+== Versão atual : %s
+
+Custom colors
+== Cores personalizadas
+
+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
+
+Force vote
+== Forçar
+
+Fullscreen
+== Tela cheia
+
+Game
+== Jogo
+
+Game info
+== Info sobre o jogo
+
+Game over
+== Fim de Jogo
+
+Game type
+== Tipo de jogo
+
+Game types:
+== Tipos de jogo:
+
+General
+== Geral
+
+Graphics
+== Gráficos
+
+Grenade
+== Granada
+
+Hammer
+== Martelo
+
+Has people playing
+== Tem gente jogando
+
+High Detail
+== Mais detalhes (HD)
+
+Hook
+== Gancho
+
+Host address
+== Endereço do host
+
+Hue
+== Matiz
+
+Info
+== Info.
+
+Internet
+== Internet
+
+Join blue
+== Azul
+
+Join game
+== Entre no jogo
+
+Join red
+== Vermelho
+
+Jump
+== Pular
+
+LAN
+== LAN
+
+Language
+== Idioma
+
+Lht.
+== Luz
+
+Loading
+== Carregando
+
+MOTD
+== MOTD
+
+Map
+== Mapa
+
+Maximum ping:
+== Ping máximo:
+
+Miscellaneous
+== Diversos
+
+Mouse sens.
+== Sens. do mouse
+
+Move left
+== Esquerda
+
+Move right
+== Direita
+
+Movement
+== Movimento
+
+Mute when not active
+== Silenciar quando inativo
+
+Name
+== Nome
+
+News
+== Notícia
+
+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
+
+Password
+== Senha
+
+Password incorrect
+== Senha incorreta
+
+Ping
+== Ping
+
+Pistol
+== Pistola
+
+Play
+== Assistir
+
+Player
+== Jogador
+
+Players
+== Jogadores
+
+Please balance teams!
+== Por favor, balanceie os times!
+
+Prev. weapon
+== Arma anterior
+
+Quality Textures
+== Texturas de Qualidade
+
+Quick search:
+== Pesquisa rápida:
+
+Quit
+== Sair
+
+Red team
+== Time vermelho
+
+Red team wins!
+== Time vermelho vence!
+
+Refresh
+== Atualizar
+
+Refreshing master servers
+== Atualizando servidores mestres
+
+Remote console
+== Console remoto
+
+Reset filter
+== Resetar filtro
+
+Reset to defaults
+== Resetar para padrão
+
+Rifle
+== Laser
+
+Round
+== Rodada
+
+Sample rate
+== Taxa de som
+
+Sat.
+== Sat.
+
+Score
+== Pontos
+
+Score board
+== Placar
+
+Score limit
+== Placar máx.
+
+Scoreboard
+== Placar
+
+Screenshot
+== Captura de tela
+
+Server details
+== Detalhes do server
+
+Server info
+== Info do server
+
+Server not full
+== Servidor não cheio
+
+Settings
+== Configurações
+
+Shotgun
+== Espingarda
+
+Show chat
+== Mostrar conversa
+
+Show name plates
+== Mostrar apelidos
+
+Show only supported
+== Mostrar apenas suportados
+
+Skins
+== Skins
+
+Sound
+== Som
+
+Sound volume
+== Volume do som
+
+Spectate
+== Observar
+
+Spectators
+== Observadores
+
+Standard gametype
+== Tipo de jogo padrão
+
+Standard map
+== Mapa padrão
+
+Sudden Death
+== Morte Súbita
+
+Switch weapon on pickup
+== Trocar arma ao pegar
+
+Team
+== Time
+
+Team chat
+== Conv. de equipe
+
+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 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.
+
+Time limit
+== Tempo máx.
+
+Try again
+== Tente de novo
+
+Type
+== Tipo
+
+UI Color
+== Cor do menu
+
+Use sounds
+== Usar sons
+
+V-Sync
+== V-Sync
+
+Version
+== Versã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
+
+##### needs translation #####
+
+%d Bytes
+== %d Bytes
+
+%d%% loaded
+== %d%% carregado
+
+%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-
+
+Add
+== Adicionar
+
+Add Friend
+== Adicionar Amigo
+
+Are you sure that you want to delete the demo?
+== Tem certeza que deseja deletar o demo?
+
+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?
+
+Automatically record demos
+== Gravar demos automaticamente
+
+Automatically take game over screenshot
+== Capturar tela final de jogo automaticamente
+
+Change settings
+== Mudar configurações
+
+Clan
+== Clan
+
+Client
+== Cliente
+
+Count players only
+== Contar apenas jogadores
+
+Country
+== País
+
+Crc:
+== Crc:
+
+Created:
+== Criado:
+
+Delete
+== Deletar
+
+Delete demo
+== Deletar demo
+
+Demo details
+== Detalhes do demo
+
+Folder
+== Pasta
+
+Free-View
+== Visão Livre
+
+Friends
+== Amigos
+
+Invalid Demo
+== Demo inválido
+
+Kick player
+== Kickar jogador
+
+Length:
+== Duração:
+
+Map:
+== Mapa:
+
+Max Screenshots
+== Máx. de Capturas de Tela
+
+Max demos
+== Máx. de demos
+
+Move player to spectators
+== Mover jogador para observadores
+
+Name plates size
+== Tamanho dos apelidos
+
+Netversion:
+== Netversion
+
+New name:
+== Novo nome:
+
+Open
+== Abrir
+
+Parent Folder
+== Diretório pai
+
+Player options
+== Opções do jogador
+
+Quit anyway?
+== Sair mesmo assim?
+
+REC %3d:%02d
+== REC %3d:%02d
+
+Reason:
+== Motivo:
+
+Record demo
+== Gravar demo
+
+Remove
+== Deletar
+
+Remove friend
+== Deletar amigo
+
+Rename
+== Renomear
+
+Rename demo
+== Renomear demo
+
+Server address:
+== Endereço do server:
+
+Server filter
+== Filtro de server
+
+Show friends
+== Mostrar amigos
+
+Show ingame HUD
+== Mostrar HUD do jogo
+
+Size:
+== Tamanho:
+
+Sound error
+== Erro de som
+
+Spectator mode
+== Modo Observador
+
+Stop record
+== Parar de gravar
+
+The audio device couldn't be initialised.
+== O aparelho de áudio não pode ser inicializado.
+
+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: %d min
+== Limite de tempo: %d min
+
+Type:
+== Tipo:
+
+Unable to delete the demo
+== Incapaz de deletar demo
+
+Unable to rename the demo
+== Incapaz de renomear demo
+
+Use team colors for name plates
+== Usar cores do time para apelidos
+
+Version:
+== Versão
+
+Vote command:
+== Comando:
+
+Vote description:
+== Descrição da votação:
+
+no limit
+== sem limite
+
+##### old translations #####
\ No newline at end of file
diff --git a/data/languages/romanian.txt b/data/languages/romanian.txt
new file mode 100644
index 0000000..3f589dc
--- /dev/null
+++ b/data/languages/romanian.txt
@@ -0,0 +1,661 @@
+
+##### translated strings #####
+
+%d Bytes
+== %d octeți
+
+%d of %d servers, %d players
+== %d/%d servere, %d jucători
+
+%d%% loaded
+== %d%% încărcat
+
+%ds left
+== %ds a ieșit
+
+%i minute left
+== %i minute rămas
+
+%i minutes left
+== %i minutes rămase
+
+%i second left
+== %i secundă rămasă
+
+%i seconds left
+== %i secunde rămase
+
+%s wins!
+== %s câștigă!
+
+-Page %d-
+== -Pagina %d-
+
+Abort
+== Anulează
+
+Add
+== Adaugă
+
+Add Friend
+== Adaugă prieten
+
+Address
+== Adresa
+
+All
+== Toți
+
+Alpha
+== Alfa
+
+Always show name plates
+== Afișează întotdeauna pseudonimele
+
+Are you sure that you want to delete the demo?
+== Sigur vrei să ștergi demo-ul?
+
+Are you sure that you want to quit?
+== Sigur vrei să ieși?
+
+Are you sure that you want to remove the player from your friends list?
+== Sigur vrei să ștergi jucătorul din lista ta de prieteni?
+
+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.
+== Aceasta fiind prima lansare a jocului, te rog introdu-ți pseudonimul mai jos. E recomandat să verifici setările și să le ajustezi cum vrei înainte să intri pe un server.
+
+Automatically record demos
+== Înregistrează automat demo-uri
+
+Automatically take game over screenshot
+== Fă automat o captură de ecran la final
+
+Blue team
+== Echipa albastră
+
+Blue team wins!
+== Echipa albastră a câștigat!
+
+Body
+== Corp
+
+Call vote
+== Votează
+
+Change settings
+== Modifică setările
+
+Chat
+== Chat
+
+Clan
+== Clanul
+
+Client
+== Clientul
+
+Close
+== Închide
+
+Compatible version
+== Versiune compatibilă
+
+Connect
+== Conectează
+
+Connecting to
+== Conectare la
+
+Connection Problems...
+== Probleme la conexiune...
+
+Console
+== Consolă
+
+Controls
+== Controale
+
+Count players only
+== Numără doar jucătorii
+
+Country
+== Țara
+
+Crc:
+== Suma de control:
+
+Created:
+== Creată la data:
+
+Current
+== Curent
+
+Current version: %s
+== Versiunea actuală: %s
+
+Custom colors
+== Culori personalizate
+
+Delete
+== Șterge
+
+Delete demo
+== Șterge demonstrația
+
+Demo details
+== Detalii demo
+
+Demos
+== Demo
+
+Disconnect
+== Deconectare
+
+Disconnected
+== Deconectat
+
+Display Modes
+== Moduri de afișare
+
+Downloading map
+== Se descarcă harta
+
+Draw!
+== Egalitate!
+
+Dynamic Camera
+== Cameră dinamică
+
+Emoticon
+== Figurine
+
+Enter
+== Intră
+
+Error
+== Eroare
+
+Error loading demo
+== Eroare la încărcarea demo-ului
+
+FSAA samples
+== Eșantioane FSAA
+
+Favorite
+== Favorit
+
+Favorites
+== Favorite
+
+Feet
+== Picioare
+
+Filter
+== Filtre
+
+Fire
+== Foc
+
+Folder
+== Dosar
+
+Force vote
+== Forțează votul
+
+Free-View
+== Vizualizare liberă
+
+Friends
+== Prieteni
+
+Fullscreen
+== Ecrat complet
+
+Game
+== Joc
+
+Game info
+== Informații joc
+
+Game over
+== Final de joc
+
+Game type
+== Tip de joc
+
+Game types:
+== Tipuri de joc:
+
+General
+== General
+
+Graphics
+== Grafică
+
+Grenade
+== Grenade
+
+Hammer
+== Ciocan
+
+Has people playing
+== Are jucători activi
+
+High Detail
+== Detalii înalte
+
+Hook
+== Cârlig
+
+Host address
+== Adresa gazdei
+
+Hue
+== Tentă
+
+Info
+== Informații
+
+Internet
+== Internet
+
+Invalid Demo
+== Demo nevalid
+
+Join blue
+== La albaștri
+
+Join game
+== Intră în joc
+
+Join red
+== La roșii
+
+Jump
+== Salt
+
+Kick player
+== Dă afară jucător
+
+LAN
+== Rețea
+
+Language
+== Limba
+
+Length:
+== Durată:
+
+Lht.
+== Luminozitate
+
+Loading
+== Se încarcă
+
+MOTD
+== Mesajul zilei
+
+Map
+== Hartă
+
+Map:
+== Harta:
+
+Max Screenshots
+== Număr maxim de capturi de ecran
+
+Max demos
+== Număr maxim de demo-uri
+
+Maximum ping:
+== Ping maxim:
+
+Miscellaneous
+== Diverse
+
+Mouse sens.
+== Sensib. maus
+
+Move left
+== Mută la stânga
+
+Move player to spectators
+== Mută jucătorul la spectatori
+
+Move right
+== Mută la dreapta
+
+Movement
+== Mișcare
+
+Mute when not active
+== Mută la inactivate
+
+Name
+== Nume
+
+Name plates size
+== Dimensiune nume placă
+
+Netversion:
+== Cod rețea:
+
+New name:
+== Nume nou:
+
+News
+== Știri
+
+Next weapon
+== Arma următoare
+
+Nickname
+== Pseudonim
+
+No
+== Nu
+
+No password
+== Fără parolă
+
+No servers found
+== Nici un server găsit
+
+No servers match your filter criteria
+== Nici un server nu corespunde criteriilor
+
+Ok
+== Bine
+
+Open
+== Deschide
+
+Parent Folder
+== Dosarul părinte
+
+Password
+== Parolă
+
+Password incorrect
+== Parolă incorectă
+
+Ping
+== Ping
+
+Pistol
+== Pistol
+
+Play
+== Redă
+
+Player
+== Jucător
+
+Player options
+== Opțiuni jucător
+
+Players
+== Jucători
+
+Please balance teams!
+== Echilibrați echipele!
+
+Prev. weapon
+== Arma precedentă
+
+Quality Textures
+== Texturi de înaltă calitate
+
+Quick search:
+== Căutare rapidă:
+
+Quit
+== Ieșire
+
+Quit anyway?
+== Ieși oricum?
+
+REC %3d:%02d
+== REC %3d:%02d
+
+Reason:
+== Motiv:
+
+Record demo
+== Înreg. demo
+
+Red team
+== Echipa roșie
+
+Red team wins!
+== Echipa roșie a câștigat!
+
+Refresh
+== Reîncarcă
+
+Refreshing master servers
+== Reîncarcă serverele principale
+
+Remote console
+== Consolă server
+
+Remove
+== Șterge
+
+Remove friend
+== Șterge prietenul
+
+Rename
+== Redenumește
+
+Rename demo
+== Redenumește demo-ul
+
+Reset filter
+== Filtru implicit
+
+Reset to defaults
+== Setări implicite
+
+Rifle
+== Carabină
+
+Round
+== Runda
+
+Sample rate
+== Frecvența
+
+Sat.
+== Saturație
+
+Score
+== Scor
+
+Score board
+== Scoruri
+
+Score limit
+== Limita de scor
+
+Scoreboard
+== Scoruri
+
+Screenshot
+== Captură de ecran
+
+Server address:
+== Adresă server:
+
+Server details
+== Detalii server
+
+Server filter
+== Filtru servere:
+
+Server info
+== Info. server
+
+Server not full
+== Are locuri libere
+
+Settings
+== Setări
+
+Shotgun
+== Pușcă
+
+Show chat
+== Afișare chat
+
+Show friends
+== Arată prietenii
+
+Show ingame HUD
+== Arată scorul în joc
+
+Show name plates
+== Arată pseudonimele
+
+Show only supported
+== Arată doar modurile suportate
+
+Size:
+== Dimensiunea:
+
+Skins
+== Costume
+
+Sound
+== Sunet
+
+Sound error
+== Eroare de sunet
+
+Sound volume
+== Volum sunet
+
+Spectate
+== Spectator
+
+Spectator mode
+== Mod spectator
+
+Spectators
+== Spectatori
+
+Standard gametype
+== Jocuri standard
+
+Standard map
+== Hărți standard
+
+Stop record
+== Stop înreg.
+
+Sudden Death
+== Moarte subită
+
+Switch weapon on pickup
+== Schimbă arma la găsire
+
+Team
+== Echipa
+
+Team chat
+== Chat cu echipa
+
+Teeworlds %s is out! Download it at www.teeworlds.com!
+== Teeworlds %s este lansat! Descarcă-l de la www.teeworlds.com!
+
+Texture Compression
+== Compresie texturi
+
+The audio device couldn't be initialised.
+== Dispozitivul audio nu a putut fi inițializat.
+
+The server is running a non-standard tuning on a pure game type.
+== Serverul folosește parametri ne-standard într-un joc standard.
+
+There's an unsaved map in the editor, you might want to save it before you quit the game.
+== Există o hartă nesalvată în editor. Probabil vrei să o salvezi înainte să ieși din joc.
+
+Time limit
+== Timp limită
+
+Time limit: %d min
+== Timp limită : %d min
+
+Try again
+== Reîncearcă
+
+Type
+== Tip
+
+Type:
+== Tip:
+
+UI Color
+== Culoare meniu
+
+Unable to delete the demo
+== Nu pot șterge demo-ul
+
+Unable to rename the demo
+== Nu pot redenumi demo-ul
+
+Use sounds
+== Folosește sunetul
+
+Use team colors for name plates
+== Folosește culorile echipelor pe etichetele de nume
+
+V-Sync
+== Sincronizare verticală (V-Sync)
+
+Version
+== Versiune
+
+Version:
+== Versiune:
+
+Vote command:
+== Comandă votare:
+
+Vote description:
+== Descriere votare:
+
+Vote no
+== Votează nu
+
+Vote yes
+== Votează da
+
+Voting
+== Votare
+
+Warmup
+== Încălzire
+
+Weapon
+== Arme
+
+Welcome to Teeworlds
+== Bun venit în Teeworlds
+
+Yes
+== Da
+
+You must restart the game for all settings to take effect.
+== Trebuie să repornești jocul pentru aplicarea setărilor.
+
+Your skin
+== Costumul tău
+
+no limit
+== fără limită
+
+##### needs translation #####
+
+##### old translations #####
+
diff --git a/data/languages/russian.txt b/data/languages/russian.txt
new file mode 100644
index 0000000..dcdcd3a
--- /dev/null
+++ b/data/languages/russian.txt
@@ -0,0 +1,661 @@
+
+##### 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
+== Детали демо
+
+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
+== Имя
+
+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
+== Просмотр
+
+Player
+== Игрок
+
+Player options
+== Опции игрока
+
+Players
+== Игроки
+
+Please balance teams!
+== Сбалансируйте команды!
+
+Prev. weapon
+== Пред. оружие
+
+Quality Textures
+== Качественные текстуры
+
+Quick search:
+== Быстрый поиск:
+
+Quit
+== Выход
+
+Quit anyway?
+== Выйти?
+
+REC %3d:%02d
+== Запись %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
+== Показывать друзей
+
+Show ingame HUD
+== Показывать внутриигроврй HUD
+
+Show name plates
+== Показывать ники игроков
+
+Show only supported
+== Только поддерживаемые режимы
+
+Size:
+== Размер
+
+Skins
+== Скины
+
+Sound
+== Звук
+
+Sound error
+== Ошибка звука
+
+Sound volume
+== Громкость звука
+
+Spectate
+== Наблюдать
+
+Spectator mode
+== Режим наблюдателя
+
+Spectators
+== Наблюдатели
+
+Standard gametype
+== Стандартный тип игры
+
+Standard map
+== Стандартная карта
+
+Stop record
+== Остановить запись
+
+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 #####
+
+Name plates size
+==
+
+##### old translations #####
+
diff --git a/data/languages/serbian.txt b/data/languages/serbian.txt
new file mode 100644
index 0000000..97a23f0
--- /dev/null
+++ b/data/languages/serbian.txt
@@ -0,0 +1,661 @@
+
+##### translated strings #####
+
+%d of %d servers, %d players
+== %d od %d server(a), %d igrač(a)
+
+%ds left
+== Još %ds
+
+Abort
+== Prekini
+
+Address
+== Adresa
+
+All
+== Svi
+
+Alpha
+== Provid.
+
+Always show name plates
+== Uvek prikaži imena igrača
+
+Are you sure that you want to quit?
+== Jeste li sigurni da želite da izađete?
+
+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.
+
+Blue team
+== Plavi tim
+
+Blue team wins!
+== Plavi tim je pobedio!
+
+Body
+== Telo
+
+Call vote
+== Glasanje
+
+Chat
+== Chat
+
+Close
+== Zatvori
+
+Compatible version
+== Kompatibilna verzija
+
+Connect
+== Konektuj
+
+Connecting to
+== Konektujem na
+
+Connection Problems...
+== Problemi sa konekcijom...
+
+Console
+== Konzola
+
+Controls
+== Kontrole
+
+Current
+== Trenutno
+
+Current version: %s
+== Trenutna verzija: %s
+
+Custom colors
+== Vlastite boje
+
+Delete
+== Izbriši
+
+Demos
+== Demoi
+
+Disconnect
+== Diskonektuj
+
+Disconnected
+== Diskonektovan
+
+Display Modes
+== Rezolucija i način prikaza
+
+Downloading map
+== Preuzimam mapu
+
+Draw!
+== Nerešeno!
+
+Dynamic Camera
+== Dinamička kamera
+
+Emoticon
+== Emoticon
+
+Enter
+== Započni
+
+Error
+== Greška
+
+Error loading demo
+== Greška prilikom učitavanja demo-snimka
+
+FSAA samples
+== FSAA samples
+
+Favorite
+== Omiljen
+
+Favorites
+== Omiljeni
+
+Feet
+== Stopala
+
+Filter
+== Filter
+
+Fire
+== Pucanje
+
+Force vote
+== Obavezno glasanje
+
+Fullscreen
+== Čitav ekran
+
+Game
+== Igra
+
+Game info
+== O igri
+
+Game over
+== Igra je završena
+
+Game type
+== Tip igre
+
+Game types:
+== Tipovi igre:
+
+General
+== Opšte
+
+Graphics
+== Grafika
+
+Grenade
+== Granate
+
+Hammer
+== Čekić
+
+Has people playing
+== Server nije prazan
+
+High Detail
+== Visoki detalji
+
+Hook
+== Lanac
+
+Host address
+== Adresa servera
+
+Hue
+== Nijansa
+
+Info
+== Info
+
+Internet
+== Internet
+
+Join blue
+== U plavi tim
+
+Join game
+== Uključi se u igru
+
+Join red
+== U crveni tim
+
+Jump
+== Skok
+
+LAN
+== LAN
+
+Language
+== Jezik
+
+Lht.
+== Svetl.
+
+Loading
+== Učitavam
+
+MOTD
+== Vest dana
+
+Map
+== Mapa
+
+Maximum ping:
+== Maksimalan ping:
+
+Miscellaneous
+== Razno
+
+Mouse sens.
+== Osetljivost miša
+
+Move left
+== Nalevo
+
+Move right
+== Nadesno
+
+Movement
+== Kretanje
+
+Mute when not active
+== Bez zvuka prilikom neaktivnosti
+
+Name
+== Ime
+
+News
+== Novosti
+
+Next weapon
+== Sledeće oružje
+
+Nickname
+== Nadimak
+
+No
+== Ne
+
+No password
+== Bez lozinke
+
+No servers found
+== Nije pronađen nijedan server
+
+No servers match your filter criteria
+== Nijedan server ne odgovara zadatom kriteriju
+
+Ok
+== OK
+
+Password
+== Lozinka
+
+Password incorrect
+== Pogrešna lozinka
+
+Ping
+== Ping
+
+Pistol
+== Pištolj
+
+Play
+== Pokreni
+
+Player
+== Igrač
+
+Players
+== Igrači
+
+Please balance teams!
+== Molim uravnotežite timove!
+
+Prev. weapon
+== Prethodno oružje
+
+Quality Textures
+== Visokokvalitetne teksture
+
+Quick search:
+== Brza pretraga:
+
+Quit
+== Izlaz
+
+Red team
+== Crveni tim
+
+Red team wins!
+== Crveni tim je pobedio!
+
+Refresh
+== Osveži
+
+Refreshing master servers
+== Osvežavam master servere
+
+Remote console
+== Udaljena konzola
+
+Reset filter
+== Poništi filter
+
+Reset to defaults
+== Resetuj podešavanja
+
+Rifle
+== Laser
+
+Round
+== Runda
+
+Sample rate
+== Frekvencija
+
+Sat.
+== Zasić.
+
+Score
+== Rezultat
+
+Score board
+== Bodovi
+
+Score limit
+== Max. bodova
+
+Scoreboard
+== Bodovi
+
+Screenshot
+== Screenshot
+
+Server details
+== Podaci o serveru
+
+Server info
+== O Serveru
+
+Server not full
+== Server nije pun
+
+Settings
+== Podešavanja
+
+Shotgun
+== Sačmarica
+
+Show chat
+== Prikaži chat
+
+Show name plates
+== Prikaži imena igrača
+
+Show only supported
+== Prikaži samo podržane
+
+Skins
+== Izgled
+
+Sound
+== Zvuk
+
+Sound volume
+== Jačina zvuka
+
+Spectate
+== Posmatraj
+
+Spectators
+== Posmatrači
+
+Standard gametype
+== Standardni tip igre
+
+Standard map
+== Standardna mapa
+
+Sudden Death
+== Iznenadna smrt
+
+Switch weapon on pickup
+== Aktiviraj novo oružje prilikom uzimanja
+
+Team
+== Tim
+
+Team chat
+== Timski chat
+
+Teeworlds %s is out! Download it at www.teeworlds.com!
+== Teeworld %s je objavljen! Preuzmi ga na www.teeworlds.com!
+
+Texture Compression
+== Kompresija tekstura
+
+The server is running a non-standard tuning on a pure game type.
+== Server sadrži nestandardna podešavanja.
+
+Time limit
+== Max. vremena
+
+Try again
+== Pokušaj ponovo
+
+Type
+== Tip
+
+UI Color
+== Boja menija
+
+Use sounds
+== Aktiviraj zvuk
+
+V-Sync
+== V-Sync
+
+Version
+== Verzija
+
+Vote no
+== Ne
+
+Vote yes
+== Da
+
+Voting
+== Glasanje
+
+Warmup
+== Zagrejavanje
+
+Weapon
+== Oružje
+
+Welcome to Teeworlds
+== Dobrodošli u Teeworlds
+
+Yes
+== Da
+
+You must restart the game for all settings to take effect.
+== Morate ponovo pokrenuti igru da bi sva podešavanja bila primenjena.
+
+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
+==
+
+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
+==
+
+Player options
+==
+
+Quit anyway?
+==
+
+REC %3d:%02d
+==
+
+Reason:
+==
+
+Record demo
+==
+
+Remove
+==
+
+Remove friend
+==
+
+Rename
+==
+
+Rename demo
+==
+
+Server address:
+==
+
+Server filter
+==
+
+Show friends
+==
+
+Show ingame HUD
+==
+
+Size:
+==
+
+Sound error
+==
+
+Spectator mode
+==
+
+Stop record
+==
+
+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
+==
+
+##### old translations #####
+
diff --git a/data/languages/ukrainian.txt b/data/languages/ukrainian.txt
new file mode 100644
index 0000000..7f43c5f
--- /dev/null
+++ b/data/languages/ukrainian.txt
@@ -0,0 +1,661 @@
+
+##### translated strings #####
+
+%d of %d servers, %d players
+== %d/%d серверів, %d гравців
+
+%d%% loaded
+== %d%% завантажено
+
+%ds left
+== залишилось %d сек.
+
+Abort
+== Відміна
+
+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?
+== Ви дійсно бажаєте вийти?
+
+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.
+== Так як це ваш перший запуск гри, будь ласка, введіть свій нік у полі нижче. Також рекомендуємо перевірити налаштування гри і змінити деякі з них, перед тим, як почати грати.
+
+Blue team
+== Сині
+
+Blue team wins!
+== Сині перемогли!
+
+Body
+== Тіло
+
+Call vote
+== Голосувати
+
+Chat
+== Чат
+
+Close
+== Закрити
+
+Compatible version
+== Сумісна версія
+
+Connect
+== Під’єднатись
+
+Connecting to
+== Підключення до
+
+Connection Problems...
+== Проблеми зі з'єднанням...
+
+Console
+== Консоль
+
+Controls
+== Управління
+
+Current
+== Поточний
+
+Current version: %s
+== Поточна версія: %s
+
+Custom colors
+== Особистий колір
+
+Delete
+== Видалити
+
+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
+== Форсувати
+
+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
+== Стрибок
+
+LAN
+== LAN
+
+Language
+== Мова
+
+Lht.
+== Яскравість
+
+Loading
+== Завантиження
+
+MOTD
+== MOTD
+
+Map
+== Карта
+
+Maximum ping:
+== Макс. пінг:
+
+Miscellaneous
+== Додатково
+
+Mouse sens.
+== Чутлив. миші
+
+Move left
+== Вліво
+
+Move right
+== Вправо
+
+Movement
+== Переміщення
+
+Mute when not active
+== Глушити звуки, коли гра неактивна
+
+Name
+== Імя
+
+News
+== Новини
+
+Next weapon
+== Наступ. зброя
+
+Nickname
+== Нік
+
+No
+== Ні
+
+No password
+== Без пароля
+
+No servers found
+== Сервера не знайдені
+
+No servers match your filter criteria
+== Не знайдено ні одного сервара, який би відповідав вашим критеріям
+
+Ok
+== Ок
+
+Open
+== Відкрити
+
+Password
+== Пароль
+
+Password incorrect
+== пароль введено невірно
+
+Ping
+== Пінг
+
+Pistol
+== Пістолет
+
+Play
+== Перегляд
+
+Player
+== Гравець
+
+Players
+== Гравці
+
+Please balance teams!
+== Збалансуйте команди!
+
+Prev. weapon
+== Попер. зброя
+
+Quality Textures
+== Якісні текстури
+
+Quick search:
+== Швидкий пошук:
+
+Quit
+== Вихід
+
+Reason:
+== Причина:
+
+Record demo
+== Запис демо
+
+Red team
+== Червоні
+
+Red team wins!
+== Червоні перемогли!
+
+Refresh
+== Оновити
+
+Refreshing master servers
+== Оновлення списку майстер-сервера
+
+Remote console
+== Консоль сервера
+
+Reset filter
+== Сикнути фільтри
+
+Reset to defaults
+== Скинути налаштування
+
+Rifle
+== Лазер
+
+Round
+== Раунд
+
+Sample rate
+== Частота
+
+Sat.
+== Контраст.
+
+Score
+== Очки
+
+Score board
+== Табло
+
+Score limit
+== Ліміт очок
+
+Scoreboard
+== Хід гри
+
+Screenshot
+== Скріншот
+
+Server details
+== Деталі сервера
+
+Server info
+== Інформація
+
+Server not full
+== Сервер не заповнений
+
+Settings
+== Налаштування
+
+Shotgun
+== Дробовик
+
+Show chat
+== Показати чат
+
+Show name plates
+== Показувати ніки гравців
+
+Show only supported
+== Тільки підтримувані режими
+
+Skins
+== Скіни
+
+Sound
+== Звук
+
+Sound volume
+== Гучність звуку
+
+Spectate
+== Спостерігати
+
+Spectators
+== Спостерігачі
+
+Standard gametype
+== Стандартний тип гри
+
+Standard map
+== Стандартна карта
+
+Stop record
+== Зупинити запис
+
+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 server is running a non-standard tuning on a pure game type.
+== Сервер запущено з нестандартними налаштуваннями на стандартному типі гри.
+
+Time limit
+== Ліміт часу
+
+Time limit: %d min
+== Ліміт часу: %d хв
+
+Try again
+== Спробувати знову
+
+Type
+== Тип
+
+UI Color
+== колір інтерфейсу
+
+Use sounds
+== Використовувати звуки
+
+V-Sync
+== Вертикальна синхронізація
+
+Version
+== Версія
+
+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
+== Ваш скін
+
+##### needs translation #####
+
+%d Bytes
+==
+
+%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 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
+==
+
+Free-View
+==
+
+Friends
+==
+
+Kick player
+==
+
+Length:
+==
+
+Map:
+==
+
+Max Screenshots
+==
+
+Max demos
+==
+
+Move player to spectators
+==
+
+Name plates size
+==
+
+Netversion:
+==
+
+New name:
+==
+
+Parent Folder
+==
+
+Player options
+==
+
+Quit anyway?
+==
+
+REC %3d:%02d
+==
+
+Remove
+==
+
+Remove friend
+==
+
+Rename
+==
+
+Rename demo
+==
+
+Server address:
+==
+
+Server filter
+==
+
+Show friends
+==
+
+Show ingame HUD
+==
+
+Size:
+==
+
+Sound error
+==
+
+Spectator mode
+==
+
+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.
+==
+
+Type:
+==
+
+Unable to delete the demo
+==
+
+Unable to rename the demo
+==
+
+Use team colors for name plates
+==
+
+Version:
+==
+
+Vote command:
+==
+
+Vote description:
+==
+
+no limit
+==
+
+##### old translations #####
+
diff --git a/scripts/commands.pl b/scripts/commands.pl
new file mode 100755
index 0000000..a2ab7a5
--- /dev/null
+++ b/scripts/commands.pl
@@ -0,0 +1,212 @@
+#!/usr/bin/perl
+
+use Cwd;
+
+@int_data = qw(default min max description);
+@str_data = qw(default description);
+
+sub strip_quotes {
+ for ($_[0]) {
+ s/^"//;
+ s/"$//;
+ return $_;
+ };
+};
+
+sub cpp {
+ open my $result,
+ '-|',
+ 'cpp '
+ . join ' ', map { "'$_'" } (
+ '-I', '.',
+ '-iquote', '/usr/include/SDL',
+ '-I', '/usr/include/freetype2',
+ @_
+ )
+ or die "cpp $_[-1]: $!\n";
+ return $result;
+};
+
+sub read_variables {
+ my %int;
+ my %str;
+ foreach my $file ('engine/shared/config_variables.h', 'game/variables.h') {
+ my $cpp = cpp
+ '-DMACRO_CONFIG_INT(slot, command, default, min, max, flags, description)=flags@command@int@default@min@max@description',
+ '-DMACRO_CONFIG_STR(slot, command, len, default, flags, description)=flags@command@str@default@description',
+ $file;
+ while (<$cpp>) {
+ next if /^#/ || /^\s*$/;
+ chomp;
+ my @data = split /@/;
+ next unless shift(@data) =~ /CFGFLAG_SERVER/;
+ my $command = shift @data;
+ strip_quotes $data[-1];
+ if (shift @data eq 'int') {
+ @{$int{$command}}{@int_data} = @data;
+ } else {
+ strip_quotes $data[0];
+ @{$str{$command}}{@str_data} = @data;
+ };
+ };
+ close $cpp or exit $? >> 8;
+ };
+ return (\%int, \%str);
+};
+
+sub do_file_tree {
+ my ($tree, $function) = @_;
+ if (-d $tree) {
+ opendir my $d, $tree or die "Cannot open dir $tree: $!\n";
+ while ($_ = readdir $d) {
+ next if $_ eq '.' || $_ eq '..';
+ do_file_tree($tree . '/' . $_, $function);
+ };
+ closedir $d;
+ } else {
+ $function->($tree);
+ };
+};
+
+sub read_commands {
+ my %commands;
+ do_file_tree '.', sub {
+ my ($file) = @_;
+ return unless $file =~ /\.cpp$/;
+ my $cpp = cpp
+ '-DRegister(command, params, flags, func, user, help)=!!REGISTER@flags@command@params@help@',
+ $file;
+ while (<$cpp>) {
+ next unless /!!REGISTER/;
+ split /@/;
+ shift;
+ next unless shift() =~ /CFGFLAG_SERVER/;
+ my ($command, $params, $help) = map { strip_quotes $_ } @_;
+ $commands{$command} = { args => $params, description => $help };
+ };
+ close $cpp or exit $? >> 8;
+ };
+ return \%commands;
+};
+
+sub max {
+ my $result = shift;
+ foreach (@_) {
+ $result = $_ if $_ > $result;
+ };
+ return $result;
+};
+
+sub print_table {
+ my ($header, $data) = @_;
+ my @keys = sort { $a cmp $b } keys %$data;
+
+ my $h0 = $header->[0];
+ my $s0 = length $h0;
+ my @h = @$header[1 .. $#{$header}];
+ my @sizes = map { length } @h;
+ foreach (@keys) {
+ for (my $i = 0; $i < @h; ++$i) {
+ $sizes[$i] = max $sizes[$i], length $data->{$_}{$h[$i]};
+ };
+ $s0 = max $s0, length;
+ };
+
+ my $f;
+ $f .= ' | %-' . $_ . 's' foreach @sizes;
+ my $h = sprintf '%-' . ($s0 + 2) . 's' . $f,
+ map { (my $x = $_) =~ s/./uc($&)/e; $x } @$header;
+ print $h, "\n";
+ $h =~ s/[^|]/-/g;
+ print $h, "\n";
+ $f .= "\n";
+ foreach (@keys) {
+ print '`', $_, '`', ' ' x ($s0 - length);
+ printf $f, @{$data->{$_}}{@h};
+ };
+};
+
+sub make_footnotes {
+ my $index = keys %footnote || 1;
+ while ($_ = shift) {
+ $footnote{$_}{ref} = '[(' . $index++ . ")][$_]";
+ $footnote{$_}{text} = shift;
+ };
+};
+
+sub footnote {
+ my ($variable, $note) = @_;
+ exists $footnote{$note} or die "No such footnote: $note\n";
+ $variable->{description} .= ' ' . $footnote{$note}->{ref};
+};
+
+sub print_footnotes {
+ my $index = sub { $_[0] =~ /\[\((\d+)\)\]/; return $1 };
+ my @refs = sort {
+ $index->($footnote{$a}{ref}) <=> $index->($footnote{$b}{ref})
+ } keys %footnote;
+ my $w = 0;
+ $w = max $w, length foreach @refs;
+ print "[$_]: ", ' ' x ($w - length), '#', $_, "\n" foreach @refs;
+ print "\n";
+ print '(', $index->($footnote{$_}->{ref}), ') ',
+ ' ' x ($w - length), $footnote{$_}{text}, "\n\n"
+ foreach @refs;
+};
+
+$root = $0;
+$root =~ s#scripts/[^/]*##;
+$root .= 'src';
+chdir $root or die "Cannot chdir to $root: $!\n";
+
+($int, $str) = read_variables;
+$commands = read_commands '.';
+
+foreach (keys %$commands) {
+ delete $commands->{$_} if exists($int->{$_}) || exists($str->{$_});
+};
+
+make_footnotes
+ boolean => 'This is a boolean value. 0 means disabled, 1—enabled.',
+ zero => 'Zero value disables this option.';
+
+foreach (values %$int) {
+ if ($_->{min} == 0 && $_->{max} == 1) {
+ footnote $_, 'boolean';
+ } elsif ($_->{max} == 0) {
+ $_->{max} = '—';
+ }
+};
+
+footnote $int->{$_}, 'zero'
+ foreach qw(
+ sv_fb_owngoal_kick
+ sv_inactivekick_time
+ sv_scorelimit
+ sv_teambalance_time
+ sv_timelimit
+ );
+
+print <new(
+ use_metadata => 1,
+ strip_metadata => 1
+);
+
+$body = $m->markdown(join '', <>);
+
+print <
+
+
+
+END
+
+print " $_\n" if $_ = $m->{'_metadata'}->{'title'};
+
+print <
+
+$body
+
+
+END
diff --git a/src/game/server/entities/character.cpp b/src/game/server/entities/character.cpp
index b40e768..8d2a73f 100644
--- a/src/game/server/entities/character.cpp
+++ b/src/game/server/entities/character.cpp
@@ -7,7 +7,9 @@
#include "character.h"
#include "laser.h"
+
#include "projectile.h"
+#include
//input count
struct CInputCount
@@ -35,7 +37,6 @@ CInputCount CountInput(int Prev, int Cur)
return c;
}
-
MACRO_ALLOC_POOL_ID_IMPL(CCharacter, MAX_CLIENTS)
// Character, "physical" player's part
@@ -60,6 +61,11 @@ bool CCharacter::Spawn(CPlayer *pPlayer, vec2 Pos)
m_LastWeapon = WEAPON_HAMMER;
m_QueuedWeapon = -1;
+ m_pBall = NULL;
+ m_GoalCampTick = 0;
+ m_CampTick = 0;
+ m_CampPos = Pos;
+
m_pPlayer = pPlayer;
m_Pos = Pos;
@@ -112,7 +118,7 @@ bool CCharacter::IsGrounded()
void CCharacter::HandleNinja()
{
- if(m_ActiveWeapon != WEAPON_NINJA)
+ if(m_ActiveWeapon != WEAPON_NINJA || m_pBall)
return;
vec2 Direction = normalize(vec2(m_LatestInput.m_TargetX, m_LatestInput.m_TargetY));
@@ -120,12 +126,7 @@ void CCharacter::HandleNinja()
if ((Server()->Tick() - m_Ninja.m_ActivationTick) > (g_pData->m_Weapons.m_Ninja.m_Duration * Server()->TickSpeed() / 1000))
{
// time's up, return
- m_aWeapons[WEAPON_NINJA].m_Got = false;
- m_ActiveWeapon = m_LastWeapon;
- if(m_ActiveWeapon == WEAPON_NINJA)
- m_ActiveWeapon = WEAPON_GUN;
-
- SetWeapon(m_ActiveWeapon);
+ RevokeNinja();
return;
}
@@ -191,8 +192,37 @@ void CCharacter::HandleNinja()
}
return;
+};
+
+void CCharacter::ReleaseBall()
+{
+ m_pBall->m_DropTick = Server()->Tick();
+ m_pBall->m_IdleTick = -1;
+ m_pBall->m_pLastCarrier = GetPlayer();
+ m_pBall->m_LastCarrierTeam = m_pBall->m_pLastCarrier->GetTeam();
+ m_pBall->m_pCarryingCharacter = NULL;
+ m_pBall = NULL;
+
+ RevokeNinja();
+}
+
+void CCharacter::DropBall()
+{
+ m_pBall->m_Vel = vec2(0, 0);
+ ReleaseBall();
+}
+
+void CCharacter::ThrowBall(vec2 direction)
+{
+ if (!m_pBall) return;
+ m_pBall->m_Vel = direction;
+ ReleaseBall();
}
+void CCharacter::CaptureBall(CBall* ball)
+{
+ static_cast(GameServer()->m_pController)->GrantBall(this, ball);
+}
void CCharacter::DoWeaponSwitch()
{
@@ -409,15 +439,27 @@ void CCharacter::FireWeapon()
} break;
case WEAPON_NINJA:
- {
- // reset Hit objects
- m_NumObjectsHit = 0;
-
- m_Ninja.m_ActivationDir = Direction;
- m_Ninja.m_CurrentMoveTime = g_pData->m_Weapons.m_Ninja.m_Movetime * Server()->TickSpeed() / 1000;
- m_Ninja.m_OldVelAmount = length(m_Core.m_Vel);
+ {
+ if (m_pBall)
+ {
+ ThrowBall(normalize (vec2 (m_LatestInput.m_TargetX, m_LatestInput.m_TargetY)) * static_cast (g_Config.m_SvfbBallVelocity / 10.0f)); //20.75f;
+ GameServer()->CreateSoundGlobal(SOUND_CTF_DROP);
+ m_ReloadTimer = g_pData->m_Weapons.m_aId[m_ActiveWeapon].m_Firedelay * Server()->TickSpeed() / 1000; // prevent shooting
+ return;
+ }
+ else
+ {
+ m_AttackTick = Server()->Tick();
+ m_Ninja.m_ActivationDir = Direction;
+ m_Ninja.m_CurrentMoveTime = g_pData->m_Weapons.m_Ninja.m_Movetime * Server()->TickSpeed() / 1000;
+ m_Ninja.m_OldVelAmount = length(m_Core.m_Vel);
+
+ // reset Hit objects
+ m_NumObjectsHit = 0;
+
+ GameServer()->CreateSound(m_Pos, SOUND_NINJA_FIRE);
+ }
- GameServer()->CreateSound(m_Pos, SOUND_NINJA_FIRE);
} break;
}
@@ -485,17 +527,31 @@ bool CCharacter::GiveWeapon(int Weapon, int Ammo)
return false;
}
-void CCharacter::GiveNinja()
+void CCharacter::BecomeNinja()
{
m_Ninja.m_ActivationTick = Server()->Tick();
m_aWeapons[WEAPON_NINJA].m_Got = true;
m_aWeapons[WEAPON_NINJA].m_Ammo = -1;
m_LastWeapon = m_ActiveWeapon;
m_ActiveWeapon = WEAPON_NINJA;
-
+}
+
+void CCharacter::GiveNinja()
+{
+ BecomeNinja();
GameServer()->CreateSound(m_Pos, SOUND_PICKUP_NINJA);
}
+void CCharacter::RevokeNinja()
+{
+ m_aWeapons[WEAPON_NINJA].m_Got = false;
+ m_ActiveWeapon = m_LastWeapon;
+ if(m_ActiveWeapon == WEAPON_NINJA)
+ m_ActiveWeapon = WEAPON_GUN;
+
+ SetWeapon(m_ActiveWeapon);
+}
+
void CCharacter::SetEmote(int Emote, int Tick)
{
m_EmoteType = Emote;
@@ -545,6 +601,54 @@ void CCharacter::Tick()
m_Core.m_Input = m_Input;
m_Core.Tick(true);
+ // direct pass of ball
+ if (g_Config.m_SvfbDirectPass && m_pBall && m_Core.m_TriggeredEvents & COREEVENT_HOOK_ATTACH_PLAYER && m_Core.m_HookedPlayer != -1)
+ {
+ CCharacter *catcher = GameServer()->m_apPlayers[m_Core.m_HookedPlayer]->GetCharacter();
+ if (!catcher->m_pBall)
+ {
+ CBall *ball = m_pBall;
+ ReleaseBall();
+ catcher->CaptureBall(ball);
+
+ // release hook
+ m_Core.m_HookedPlayer = -1;
+ m_Core.m_HookState = HOOK_RETRACTED;
+ m_Core.m_HookPos = m_Core.m_Pos;
+ }
+ };
+
+ // hook the flag
+ if (g_Config.m_SvfbHookBall && !m_pBall && (m_Core.m_HookState == HOOK_FLYING || m_Core.m_TriggeredEvents & (COREEVENT_HOOK_ATTACH_GROUND + COREEVENT_HOOK_HIT_NOHOOK)))
+ {
+ // Find the closest ball
+ CBall *closest_ball = NULL;
+ for (int i = 0; i < FB_MAX_BALLS; ++i)
+ {
+ CBall *b = static_cast(GameServer()->m_pController)->m_apBalls[i];
+ if (b && !b->m_pCarryingCharacter)
+ {
+ // It may be not a good idea to pass this to
+ // config, but we need some easy way to test
+ // these values
+ static vec2 ball_offset(0, -38);
+ vec2 ball_pos = b->m_Pos + ball_offset;
+ vec2 closest_point = closest_point_on_line(m_Core.m_Pos, m_Core.m_HookPos, ball_pos);
+ if (distance(ball_pos, closest_point) < g_Config.m_SvfbBallRadius && (!closest_ball || distance(m_Pos, ball_pos) < distance(m_Pos, closest_ball->m_Pos)))
+ {
+ closest_ball = b;
+ };
+ };
+ };
+ if (closest_ball)
+ {
+ CaptureBall(closest_ball);
+ // retract hook
+ m_Core.m_HookState = HOOK_RETRACTED;
+ m_Core.m_HookPos = m_Core.m_Pos;
+ };
+ };
+
// handle death-tiles and leaving gamelayer
if(GameServer()->Collision()->GetCollisionAt(m_Pos.x+m_ProximityRadius/3.f, m_Pos.y-m_ProximityRadius/3.f)&CCollision::COLFLAG_DEATH ||
GameServer()->Collision()->GetCollisionAt(m_Pos.x+m_ProximityRadius/3.f, m_Pos.y+m_ProximityRadius/3.f)&CCollision::COLFLAG_DEATH ||
@@ -701,6 +805,16 @@ bool CCharacter::TakeDamage(vec2 Force, int Dmg, int From, int Weapon)
if(GameServer()->m_pController->IsFriendlyFire(m_pPlayer->GetCID(), From) && !g_Config.m_SvTeamdamage)
return false;
+ // do damage Hit sound
+ if(From >= 0 && From != m_pPlayer->GetCID() && GameServer()->m_apPlayers[From])
+ GameServer()->CreateSound(GameServer()->m_apPlayers[From]->m_ViewPos, SOUND_HIT, CmaskOne(From));
+
+ if (g_Config.m_SvfbInstagib && Weapon == WEAPON_RIFLE)
+ {
+ Die(From, Weapon);
+ return true;
+ }
+
// m_pPlayer only inflicts half damage on self
if(From == m_pPlayer->GetCID())
Dmg = max(1, Dmg/2);
@@ -746,10 +860,6 @@ bool CCharacter::TakeDamage(vec2 Force, int Dmg, int From, int Weapon)
m_DamageTakenTick = Server()->Tick();
- // do damage Hit sound
- if(From >= 0 && From != m_pPlayer->GetCID() && GameServer()->m_apPlayers[From])
- GameServer()->CreateSound(GameServer()->m_apPlayers[From]->m_ViewPos, SOUND_HIT, CmaskOne(From));
-
// check for death
if(m_Health <= 0)
{
@@ -768,6 +878,12 @@ bool CCharacter::TakeDamage(vec2 Force, int Dmg, int From, int Weapon)
return false;
}
+ else
+ {
+ // lose flag on every damage
+ if (m_pBall && g_Config.m_SvfbBallDamageLose)
+ ReleaseBall();
+ }
if (Dmg > 2)
GameServer()->CreateSound(m_Pos, SOUND_PLAYER_PAIN_LONG);
diff --git a/src/game/server/entities/character.h b/src/game/server/entities/character.h
index b400905..f94ae2c 100644
--- a/src/game/server/entities/character.h
+++ b/src/game/server/entities/character.h
@@ -54,24 +54,27 @@ public:
bool IncreaseHealth(int Amount);
bool IncreaseArmor(int Amount);
+ // flagball
+ class CBall* m_pBall;
+ int m_GoalCampTick; // goal camp counter
+ int m_CampTick; // camp counter
+ vec2 m_CampPos;
+ void ReleaseBall();
+ void DropBall();
+ void ThrowBall(vec2 direction);
+ void CaptureBall(CBall *);
+
+ int m_Health;
bool GiveWeapon(int Weapon, int Ammo);
- void GiveNinja();
+ void GiveNinja(); // GiveNinja calls BecomeNinja and makes the sound
+ void BecomeNinja();
+ void RevokeNinja();
void SetEmote(int Emote, int Tick);
bool IsAlive() const { return m_Alive; }
class CPlayer *GetPlayer() { return m_pPlayer; }
-
-private:
- // player controlling this character
- class CPlayer *m_pPlayer;
-
- bool m_Alive;
- // weapon info
- CEntity *m_apHitObjects[10];
- int m_NumObjectsHit;
-
struct WeaponStat
{
int m_AmmoRegenStart;
@@ -83,9 +86,20 @@ private:
int m_ActiveWeapon;
int m_LastWeapon;
- int m_QueuedWeapon;
int m_ReloadTimer;
+private:
+ // player controlling this character
+ class CPlayer *m_pPlayer;
+
+ bool m_Alive;
+
+ // weapon info
+ CEntity *m_apHitObjects[10];
+ int m_NumObjectsHit;
+
+ int m_QueuedWeapon;
+
int m_AttackTick;
int m_DamageTaken;
@@ -108,7 +122,6 @@ private:
int m_DamageTakenTick;
- int m_Health;
int m_Armor;
// ninja
diff --git a/src/game/server/entities/laser.cpp b/src/game/server/entities/laser.cpp
index 184702c..34a3c15 100644
--- a/src/game/server/entities/laser.cpp
+++ b/src/game/server/entities/laser.cpp
@@ -3,6 +3,8 @@
#include
#include
#include "laser.h"
+#include
+#include
CLaser::CLaser(CGameWorld *pGameWorld, vec2 Pos, vec2 Direction, float StartEnergy, int Owner)
: CEntity(pGameWorld, CGameWorld::ENTTYPE_LASER)
@@ -28,11 +30,30 @@ bool CLaser::HitCharacter(vec2 From, vec2 To)
m_From = From;
m_Pos = At;
+ hit_ball(From, m_Pos);
m_Energy = -1;
Hit->TakeDamage(vec2(0.f, 0.f), GameServer()->Tuning()->m_LaserDamage, m_Owner, WEAPON_RIFLE);
return true;
}
+void CLaser::hit_ball(vec2 from, vec2 to) {
+ if (g_Config.m_SvfbLaserMomentum == 0) return;
+ for (int i = 0; i < FB_MAX_BALLS; ++i)
+ {
+ CBall *ball = static_cast(GameServer()->m_pController)->m_apBalls[i];
+ if (!ball || ball->m_pCarryingCharacter) continue;
+ vec2 ball_pos = ball->m_Pos + vec2(g_Config.m_SvfbBallOffsetX, -g_Config.m_SvfbBallOffsetY);
+ if (distance(ball_pos, closest_point_on_line(from, to, ball_pos)) < g_Config.m_SvfbBallRadius)
+ {
+ ball->m_Vel += normalize(to - from) * g_Config.m_SvfbLaserMomentum * 0.1f;
+ ball->m_DropTick = Server()->Tick();
+ ball->m_pLastCarrier = GameServer()->m_apPlayers[m_Owner];
+ ball->m_LastCarrierTeam = GameServer()->m_apPlayers[m_Owner]->GetTeam();
+ static_cast(GameServer()->m_pController)->SetBallColor(ball, ball->m_LastCarrierTeam);
+ }
+ };
+};
+
void CLaser::DoBounce()
{
m_EvalTick = Server()->Tick();
@@ -50,6 +71,7 @@ void CLaser::DoBounce()
{
if(!HitCharacter(m_Pos, To))
{
+ hit_ball(m_Pos, To);
// intersected
m_From = m_Pos;
m_Pos = To;
@@ -74,6 +96,7 @@ void CLaser::DoBounce()
{
if(!HitCharacter(m_Pos, To))
{
+ hit_ball(m_Pos, To);
m_From = m_Pos;
m_Pos = To;
m_Energy = -1;
diff --git a/src/game/server/entities/laser.h b/src/game/server/entities/laser.h
index 91ba5df..2c38fe1 100644
--- a/src/game/server/entities/laser.h
+++ b/src/game/server/entities/laser.h
@@ -16,6 +16,7 @@ public:
protected:
bool HitCharacter(vec2 From, vec2 To);
+ void hit_ball(vec2 from, vec2 to);
void DoBounce();
private:
diff --git a/src/game/server/gamecontext.cpp b/src/game/server/gamecontext.cpp
index a0c1c64..917028f 100644
--- a/src/game/server/gamecontext.cpp
+++ b/src/game/server/gamecontext.cpp
@@ -13,6 +13,7 @@
#include "gamemodes/tdm.h"
#include "gamemodes/ctf.h"
#include "gamemodes/mod.h"
+#include "gamemodes/fb.h"
enum
{
@@ -380,6 +381,7 @@ void CGameContext::SendTuningParams(int ClientID)
void CGameContext::OnTick()
{
+
// check tuning
CheckPureTuning();
@@ -512,6 +514,18 @@ void CGameContext::OnClientEnter(int ClientID)
SendChat(-1, CGameContext::CHAT_ALL, aBuf);
str_format(aBuf, sizeof(aBuf), "team_join player='%d:%s' team=%d", ClientID, Server()->ClientName(ClientID), m_apPlayers[ClientID]->GetTeam());
+
+ if (str_comp(m_pController->m_pGameType, "FB") == 0 || str_comp(m_pController->m_pGameType, "iFB") == 0)
+ {
+ // Send MOD-version string
+ str_format(aBuf, sizeof (aBuf), "FlagBall version: %s", MOD_VERSION);
+ SendChatTarget(ClientID, aBuf);
+
+ // Send welcome message
+ if (str_length(g_Config.m_SvfbWelcomeMessage))
+ SendChatTarget(ClientID, g_Config.m_SvfbWelcomeMessage);
+ }
+
Console()->Print(IConsole::OUTPUT_LEVEL_DEBUG, "game", aBuf);
m_VoteUpdate = true;
@@ -943,7 +957,7 @@ void CGameContext::OnMessage(int MsgID, CUnpacker *pUnpacker, int ClientID)
SendEmoticon(ClientID, pMsg->m_Emoticon);
}
- else if (MsgID == NETMSGTYPE_CL_KILL && !m_World.m_Paused)
+ else if (MsgID == NETMSGTYPE_CL_KILL && !m_World.m_Paused && g_Config.m_SvfbSelfKill)
{
if(pPlayer->m_LastKill && pPlayer->m_LastKill+Server()->TickSpeed()*3 > Server()->Tick())
return;
@@ -1278,6 +1292,11 @@ void CGameContext::ConVote(IConsole::IResult *pResult, void *pUserData)
pSelf->Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "server", aBuf);
}
+void CGameContext::ConNextMap(IConsole::IResult *pResult, void *pUserData)
+{
+ ((CGameContext *)pUserData)->m_pController->NextMap();
+}
+
void CGameContext::ConchainSpecialMotdupdate(IConsole::IResult *pResult, void *pUserData, IConsole::FCommandCallback pfnCallback, void *pCallbackUserData)
{
pfnCallback(pResult, pCallbackUserData);
@@ -1314,6 +1333,8 @@ void CGameContext::OnConsoleInit()
Console()->Register("clear_votes", "", CFGFLAG_SERVER, ConClearVotes, this, "");
Console()->Register("vote", "r", CFGFLAG_SERVER, ConVote, this, "");
+ Console()->Register("next_map", "", CFGFLAG_SERVER, ConNextMap, this, "Switch to another random map");
+
Console()->Chain("sv_motd", ConchainSpecialMotdupdate, this);
}
@@ -1338,7 +1359,9 @@ void CGameContext::OnInit(/*class IKernel *pKernel*/)
//players = new CPlayer[MAX_CLIENTS];
// select gametype
- if(str_comp(g_Config.m_SvGametype, "mod") == 0)
+ if (str_comp(g_Config.m_SvGametype, "fb") == 0)
+ m_pController = new CGameControllerFB(this);
+ else if(str_comp(g_Config.m_SvGametype, "mod") == 0)
m_pController = new CGameControllerMOD(this);
else if(str_comp(g_Config.m_SvGametype, "ctf") == 0)
m_pController = new CGameControllerCTF(this);
diff --git a/src/game/server/gamecontext.h b/src/game/server/gamecontext.h
index 576a1b1..e597ec3 100644
--- a/src/game/server/gamecontext.h
+++ b/src/game/server/gamecontext.h
@@ -59,6 +59,7 @@ class CGameContext : public IGameServer
static void ConForceVote(IConsole::IResult *pResult, void *pUserData);
static void ConClearVotes(IConsole::IResult *pResult, void *pUserData);
static void ConVote(IConsole::IResult *pResult, void *pUserData);
+ static void ConNextMap(IConsole::IResult *pResult, void *pUserData);
static void ConchainSpecialMotdupdate(IConsole::IResult *pResult, void *pUserData, IConsole::FCommandCallback pfnCallback, void *pCallbackUserData);
CGameContext(int Resetting);
diff --git a/src/game/server/gamecontroller.cpp b/src/game/server/gamecontroller.cpp
index c5a9657..2ac12d2 100644
--- a/src/game/server/gamecontroller.cpp
+++ b/src/game/server/gamecontroller.cpp
@@ -8,7 +8,7 @@
#include "entities/pickup.h"
#include "gamecontroller.h"
#include "gamecontext.h"
-
+#include "maprotation.h"
IGameController::IGameController(class CGameContext *pGameServer)
{
@@ -265,6 +265,7 @@ void IGameController::StartRound()
m_aTeamscore[TEAM_RED] = 0;
m_aTeamscore[TEAM_BLUE] = 0;
m_ForceBalanced = false;
+
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);
@@ -293,59 +294,76 @@ void IGameController::CycleMap()
if(m_RoundCount < g_Config.m_SvRoundsPerMap-1)
return;
-
+
+ NextMap();
+}
+
+void IGameController::NextMap()
+{
// handle maprotation
const char *pMapRotation = g_Config.m_SvMaprotation;
const char *pCurrentMap = g_Config.m_SvMap;
-
- int CurrentMapLen = str_length(pCurrentMap);
- const char *pNextMap = pMapRotation;
- while(*pNextMap)
+ const char *pNextMap;
+ char aBuf[512];
+
+ if (str_comp_num(pMapRotation, "!random ", 8) == 0)
{
- int WordLen = 0;
- while(pNextMap[WordLen] && !IsSeparator(pNextMap[WordLen]))
- WordLen++;
-
- if(WordLen == CurrentMapLen && str_comp_num(pNextMap, pCurrentMap, CurrentMapLen) == 0)
+ static IMapRotation *rotation = RandomMapRotation();
+ pNextMap = rotation->NextMap(pMapRotation + 8, pCurrentMap);
+ }
+ else
+ {
+ // standard rotation
+ pNextMap = pMapRotation;
+ int CurrentMapLen = str_length(pCurrentMap);
+ while(*pNextMap)
{
- // map found
- pNextMap += CurrentMapLen;
- while(*pNextMap && IsSeparator(*pNextMap))
- pNextMap++;
-
- break;
+ int WordLen = 0;
+ while(pNextMap[WordLen] && !IsSeparator(pNextMap[WordLen]))
+ WordLen++;
+
+ if(WordLen == CurrentMapLen && str_comp_num(pNextMap, pCurrentMap, CurrentMapLen) == 0)
+ {
+ // map found
+ pNextMap += CurrentMapLen;
+ while(*pNextMap && IsSeparator(*pNextMap))
+ pNextMap++;
+
+ break;
+ }
+
+ pNextMap++;
}
- pNextMap++;
- }
-
- // restart rotation
- if(pNextMap[0] == 0)
- pNextMap = pMapRotation;
+ // restart rotation
+ if(pNextMap[0] == 0)
+ pNextMap = pMapRotation;
- // cut out the next map
- char aBuf[512];
- for(int i = 0; i < 512; i++)
- {
- aBuf[i] = pNextMap[i];
- if(IsSeparator(pNextMap[i]) || pNextMap[i] == 0)
+ // cut out the next map
+ for(int i = 0; i < 512; i++)
{
- aBuf[i] = 0;
- break;
+ aBuf[i] = pNextMap[i];
+ if(IsSeparator(pNextMap[i]) || pNextMap[i] == 0)
+ {
+ aBuf[i] = 0;
+ break;
+ }
}
+
+ // skip spaces
+ int i = 0;
+ while(IsSeparator(aBuf[i]))
+ i++;
+
+ pNextMap = &aBuf[i];
}
- // skip spaces
- int i = 0;
- while(IsSeparator(aBuf[i]))
- i++;
-
m_RoundCount = 0;
char aBufMsg[256];
- str_format(aBufMsg, sizeof(aBufMsg), "rotating map to %s", &aBuf[i]);
- GameServer()->Console()->Print(IConsole::OUTPUT_LEVEL_DEBUG, "game", aBuf);
- str_copy(g_Config.m_SvMap, &aBuf[i], sizeof(g_Config.m_SvMap));
+ str_format(aBufMsg, sizeof(aBufMsg), "rotating map to %s", pNextMap);
+ GameServer()->Console()->Print(IConsole::OUTPUT_LEVEL_DEBUG, "game", pNextMap);
+ str_copy(g_Config.m_SvMap, pNextMap, sizeof(g_Config.m_SvMap));
}
void IGameController::PostReset()
@@ -444,7 +462,9 @@ bool IGameController::IsForceBalanced()
return true;
}
else
+ {
return false;
+ }
}
bool IGameController::CanBeMovedOnBalance(int ClientID)
@@ -454,6 +474,7 @@ bool IGameController::CanBeMovedOnBalance(int ClientID)
void IGameController::Tick()
{
+
// do warmup
if(m_Warmup)
{
@@ -578,6 +599,7 @@ bool IGameController::IsTeamplay() const
void IGameController::Snap(int SnappingClient)
{
+
CNetObj_GameInfo *pGameInfoObj = (CNetObj_GameInfo *)Server()->SnapNewItem(NETOBJTYPE_GAMEINFO, 0, sizeof(CNetObj_GameInfo));
if(!pGameInfoObj)
return;
diff --git a/src/game/server/gamecontroller.h b/src/game/server/gamecontroller.h
index c999f84..2cf9886 100644
--- a/src/game/server/gamecontroller.h
+++ b/src/game/server/gamecontroller.h
@@ -59,9 +59,11 @@ protected:
int m_GameFlags;
int m_UnbalancedTick;
+
bool m_ForceBalanced;
public:
+
const char *m_pGameType;
bool IsTeamplay() const;
@@ -141,6 +143,7 @@ public:
bool CheckTeamBalance();
bool CanChangeTeam(CPlayer *pPplayer, int JoinTeam);
int ClampTeam(int Team);
+ void NextMap();
virtual void PostReset();
};
diff --git a/src/game/server/gamemodes/fb.cpp b/src/game/server/gamemodes/fb.cpp
new file mode 100644
index 0000000..0c93e07
--- /dev/null
+++ b/src/game/server/gamemodes/fb.cpp
@@ -0,0 +1,567 @@
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include "fb.h"
+
+CBall::CBall(CGameWorld *pGameWorld, int Team, vec2 Pos)
+: CFlag(pGameWorld, Team)
+{
+ m_StandPos = Pos;
+ m_Pos = Pos;
+}
+
+void CBall::Reset()
+{
+ CFlag::Reset();
+ m_pLastCarrier = NULL;
+ m_DropTick = 0;
+ m_IdleTick = -1;
+ m_LastCarrierTeam = !m_Team;
+}
+
+void CBall::Tick()
+{
+ if (!m_pCarryingCharacter && !m_AtStand)
+ {
+ if (GameLayerClipped(m_Pos) || (m_IdleTick >= 0 && Server()->Tick() > m_IdleTick + Server()->TickSpeed() * g_Config.m_SvfbBallResetTime))
+ {
+ Reset();
+ GameServer()->CreateSoundGlobal(SOUND_CTF_RETURN);
+ }
+ else
+ {
+ // do ball physics
+ m_Vel.y += GameServer()->m_World.m_Core.m_Tuning.m_Gravity;
+ if (m_Vel.x > -0.1f && m_Vel.x < 0.1f)
+ m_Vel.x = 0.0f;
+ else if (m_Vel.x < 0)
+ m_Vel.x += 0.055f;
+ else
+ m_Vel.x -= 0.055f;
+
+ float vy = m_Vel.y;
+ GameServer()->Collision()->MoveBox(&m_Pos, &m_Vel, vec2(ms_PhysSize, ms_PhysSize), 0.5f);
+ if (m_Vel.x == 0 && (vy > 0) != (m_Vel.y > 0) && abs(m_Vel.y) < GameServer()->m_World.m_Core.m_Tuning.m_Gravity)
+ {
+ if (m_IdleTick == -1)
+ m_IdleTick = Server()->Tick();
+ }
+ else
+ m_IdleTick = -1;
+ }
+ }
+}
+
+CGameControllerFB::CGameControllerFB(class CGameContext *pGameServer)
+: IGameController(pGameServer)
+{
+ m_apBalls[0] = NULL;
+ m_apBalls[1] = NULL;
+ m_pGameType = g_Config.m_SvfbInstagib ? "iFB" : "FB";
+ m_GameFlags = GAMEFLAG_TEAMS | GAMEFLAG_FLAGS;
+ m_apGoalPos[0] = vec2(0, 0);
+ m_apGoalPos[1] = vec2(0, 0);
+ m_NumGoals = 0;
+ GameServer()->Tuning()->m_LaserDamage = g_Config.m_SvfbInstagib ? 10 : 5;
+
+}
+
+bool CGameControllerFB::OnEntity (int index, vec2 pos)
+{
+
+ // don't add pickups in instagib
+ if (strcmp (m_pGameType, "iFB") == 0 && index > ENTITY_FLAGSTAND_BLUE)
+ return false;
+
+ if (IGameController::OnEntity (index, pos))
+ return true;
+
+ // add goal positions and balls
+ switch (index)
+ {
+ case ENTITY_SPAWN:
+ if (m_NumGoals < FB_MAX_GOALS)
+ m_apGoalPos[m_NumGoals++] = pos;
+ break;
+ case ENTITY_FLAGSTAND_RED:
+ if (!m_apBalls[TEAM_RED])
+ GameServer()->m_World.InsertEntity(m_apBalls[TEAM_RED] = new CBall(&GameServer()->m_World, TEAM_RED, pos));
+ break;
+ case ENTITY_FLAGSTAND_BLUE:
+ if (!m_apBalls[TEAM_BLUE])
+ GameServer()->m_World.InsertEntity(m_apBalls[TEAM_BLUE] = new CBall(&GameServer()->m_World, TEAM_BLUE, pos));
+ break;
+ default:
+ return false;
+ }
+ return true;
+
+}
+
+int CGameControllerFB::OnCharacterDeath(class CCharacter *victim, class CPlayer *killer, int weaponid)
+{
+
+ // do scoreing
+ if (weaponid == WEAPON_SELF || weaponid == WEAPON_WORLD)
+ victim->GetPlayer()->m_Score--; // suicide or death-tile
+ else if (killer && weaponid != WEAPON_GAME)
+ {
+ if (IsTeamplay() && victim->GetPlayer()->GetTeam() == killer->GetTeam())
+ killer->m_Score--; // teamkill
+ else
+ killer->m_Score++; // normal kill
+ }
+
+ int mode = 0;
+ if (killer)
+ {
+ CCharacter *const ch = killer->GetCharacter();
+ if (ch && ch->m_pBall)
+ mode |= 2;
+ };
+ if (victim->m_pBall)
+ {
+ victim->DropBall();
+ if (weaponid != WEAPON_GAME) // exclude tee goal
+ GameServer()->CreateSoundGlobal(SOUND_CTF_DROP);
+ if (killer && killer->GetTeam() != victim->GetPlayer()->GetTeam())
+ killer->m_Score++;
+ mode |= 1;
+ }
+
+ return mode;
+
+}
+
+void CGameControllerFB::OnCharacterSpawn(class CCharacter *chr)
+{
+
+ // default health
+ chr->m_Health = 10;
+
+ if (strcmp (m_pGameType, "iFB") == 0)
+ {
+ // give instagib weapon
+ chr->m_aWeapons[WEAPON_RIFLE].m_Got = 1;
+ chr->m_aWeapons[WEAPON_RIFLE].m_Ammo = -1;
+ chr->m_ActiveWeapon = WEAPON_RIFLE;
+ chr->m_LastWeapon = WEAPON_RIFLE;
+ chr->m_ReloadTimer = g_Config.m_SvfbSpawnWeaponDischarge * g_pData->m_Weapons.m_aId[WEAPON_RIFLE].m_Firedelay * Server()->TickSpeed() / (1000 * 100);
+ }
+ else
+ {
+ // give default weapons
+ chr->m_aWeapons[WEAPON_HAMMER].m_Got = 1;
+ chr->m_aWeapons[WEAPON_HAMMER].m_Ammo = -1;
+ chr->m_aWeapons[WEAPON_GUN].m_Got = 1;
+ chr->m_aWeapons[WEAPON_GUN].m_Ammo = 10;
+ }
+
+}
+
+bool CGameControllerFB::HandleGoal (CBall *b, int goal)
+{
+
+ CPlayer *const p = b->m_pCarryingCharacter ? b->m_pCarryingCharacter->GetPlayer() : b->m_pLastCarrier;
+ const int team = p ? p->GetTeam() : b->m_LastCarrierTeam;
+ const bool own_goal = team == goal;
+ const bool tee_goal = b->m_pCarryingCharacter;
+
+ // update scores
+ if (own_goal)
+ {
+ if (!g_Config.m_SvfbOwngoal)
+ return false;
+
+ if (p)
+ {
+ p->m_Score -= g_Config.m_SvfbOwngoalPenalty;
+ p->m_NumOwngoals++;
+
+ // send warning to user
+ char chat_msg[256];
+ str_format (chat_msg, sizeof (chat_msg), "!!! Hey %s, you scored an own-goal! Put the ball into the OTHER goal !!!", Server()->ClientName(p->m_ClientID));
+ GameServer()->SendChatTarget (p->m_ClientID, chat_msg);
+ }
+ // there's no sound like "wah...wah" ;)
+ GameServer()->CreateSoundGlobal(SOUND_NINJA_HIT); //SOUND_PLAYER_PAIN_LONG
+ }
+ else
+ {
+ if (p)
+ p->m_Score += tee_goal ? g_Config.m_SvfbScorePlayerTee : g_Config.m_SvfbScorePlayerBall;
+
+ GameServer()->CreateSoundGlobal(SOUND_CTF_CAPTURE);
+ }
+ m_aTeamscore[goal ^ 1] += tee_goal ? g_Config.m_SvfbScoreTeamTee : g_Config.m_SvfbScoreTeamBall;
+
+ // let the tee die if it jumped into goal... or when dumb own-goal
+ if (p && (tee_goal || own_goal))
+ p->KillCharacter (WEAPON_GAME);
+ b->Reset();
+ GameServer()->CreateSoundGlobal(SOUND_CTF_RETURN);
+
+ // Cut off long nicknames... the message would jut out on screen!
+ const int nick_length = 18;
+ char nick[64] = {0};
+ str_format (nick, sizeof (nick), "%s", p ? Server()->ClientName(p->m_ClientID) : "player left");
+ if (str_length (nick) > nick_length)
+ {
+ nick[nick_length] = 0;
+ str_append (nick, "...", sizeof (nick));
+ }
+
+ // Build broadcast-message
+ char bc_msg[512] = {0};
+ str_format (bc_msg, sizeof (bc_msg), "%s team (%s) scored with %s!", (goal ^ 1) == 0 ? "Red" : "Blue",
+ nick, tee_goal ? "tee": "ball");
+
+ // wired workaround for multiline broadcast-message center alignment
+ // FIXME: can be done smarter!
+ if (own_goal)
+ {
+ char line2[] = "\nPwned... that was an own-goal!";
+ const int fillup = 2 * (str_length (bc_msg) - (str_length (line2) - 1));
+ str_append (bc_msg, line2, sizeof (bc_msg));
+
+ if (fillup > 0)
+ {
+ char *cur_pos = bc_msg + str_length (bc_msg);
+ for (int l = 0; l < fillup; l++)
+ *cur_pos++ = ' ';
+ *cur_pos = 0;
+ }
+ }
+ // send everyone the scoring-message
+ GameServer()->SendBroadcast(bc_msg, -1);
+
+ // kick unteachable player from server
+ if (g_Config.m_SvfbOwngoalKick && p && p->m_NumOwngoals >= g_Config.m_SvfbOwngoalKick)
+ {
+ char chat_msg[256];
+ str_format (chat_msg, sizeof (chat_msg), "%s was automatically kicked. Cause: Scored too many own-goals (%d).",
+ Server()->ClientName(p->m_ClientID), g_Config.m_SvfbOwngoalKick);
+
+ Server()->Kick(p->m_ClientID,
+ "You scored too many own-goals! Please play the "
+ "game as it is supposed to be. Thank you!");
+
+ GameServer()->SendChat(-1, CGameContext::CHAT_ALL, chat_msg);
+ }
+
+ return true;
+
+}
+
+void CGameControllerFB::OnDisconnect (CPlayer *const p)
+{
+ CCharacter* ch = p->GetCharacter();
+ for (int i = 0; i < FB_MAX_BALLS; ++i)
+ {
+ if (m_apBalls[i])
+ {
+ if (ch && m_apBalls[i]->m_pCarryingCharacter == ch)
+ ch->ReleaseBall();
+ if (m_apBalls[i]->m_pLastCarrier == p)
+ m_apBalls[i]->m_pLastCarrier = NULL;
+ }
+ }
+}
+
+template void swap(T& x, T& y)
+{
+ T z = x;
+ x = y;
+ y = z;
+}
+
+void CGameControllerFB::SetBallColor(CBall *&ball, int team)
+{
+ /* The flag color cannot be changed by mere assignment to m_Team. When
+ * someone carries a repainted flag, it causes lags due to the way flag
+ * position interpolation is implemented in CItems::RenderFlag in
+ * game/client/components/items.cpp. A hackish workaround is to swap
+ * the flags when the other color is requested, but we should take
+ * special care for the maps where both flags are available */
+
+ if (!ball || ball->m_Team == team) return;
+ CBall *b = m_apBalls[team];
+ if (!b->m_AtStand) return;
+
+ swap(b->m_StandPos, ball->m_StandPos);
+ b->m_AtStand = false;
+ b->m_Pos = ball->m_Pos;
+ b->m_Vel = ball->m_Vel;
+ b->m_pCarryingCharacter = ball->m_pCarryingCharacter;
+ b->m_pLastCarrier = ball->m_pLastCarrier;
+ b->m_LastCarrierTeam = ball->m_LastCarrierTeam;
+ b->m_DropTick = ball->m_DropTick;
+ b->m_GrabTick = ball->m_GrabTick;
+ b->m_IdleTick = ball->m_IdleTick;
+
+ ball->Reset();
+ ball = b;
+}
+
+void CGameControllerFB::CreateBallGrabSound(int team)
+{
+ for (int c = 0; c < MAX_CLIENTS; ++c)
+ {
+ CPlayer *p = GameServer()->m_apPlayers[c];
+ if (!p)
+ continue;
+ GameServer()->CreateSoundGlobal(p->GetTeam() == team ? SOUND_CTF_GRAB_PL : SOUND_CTF_GRAB_EN, p->GetCID());
+ }
+}
+
+void CGameControllerFB::GrantBall(CCharacter *ch, CBall *b)
+{
+ int team = ch->GetPlayer()->GetTeam();
+ if (b->m_AtStand)
+ {
+ m_aTeamscore[team] += g_Config.m_SvfbScoreTeamStand;
+ ch->GetPlayer()->m_Score += g_Config.m_SvfbScorePlayerStand;
+ b->m_AtStand = 0;
+ }
+ b->m_pCarryingCharacter = ch;
+ b->m_Pos = ch->m_Pos;
+ if (g_Config.m_SvfbLaserMomentum)
+ SetBallColor(b, team);
+ ch->m_pBall = b;
+ ch->BecomeNinja();
+ CreateBallGrabSound(team);
+}
+
+
+void CGameControllerFB::Tick()
+{
+
+ IGameController::Tick();
+ DoTeamScoreWincheck();
+
+ if (m_GameOverTick == -1 && m_RoundStartTick != Server()->Tick())
+ {
+
+ for (int i = 0; i < MAX_CLIENTS; ++i)
+ {
+ if (!GameServer()->m_apPlayers[i]) continue;
+
+ CCharacter *ch = GameServer()->m_apPlayers[i]->GetCharacter();
+ if (!ch || !ch->IsAlive())
+ continue;
+
+ // Check for a goal-camper
+ if (g_Config.m_SvfbGoalcamp)
+ {
+ bool in_range = false;
+ for (int goal = 0; goal < m_NumGoals; ++goal)
+ {
+ if (distance (ch->m_Pos, m_apGoalPos[goal]) <
+ g_Config.m_SvfbGoalsize * static_cast (g_Config.m_SvfbGoalcampFactor / 10.0f)) // 1.5f
+ {
+ // if in range, count up 2 ticks
+ ch->m_GoalCampTick += 2;
+ in_range = true;
+ break;
+ }
+ }
+
+ if (!in_range)
+ {
+ // if out of range, count down just 1 tick again (slower)
+ if (ch->m_GoalCampTick)
+ ch->m_GoalCampTick--;
+ }
+ else
+ {
+ // kill goal camping player
+ if ((ch->m_GoalCampTick >> 1) >= Server()->TickSpeed() * g_Config.m_SvfbGoalcampTime)
+ {
+ GameServer()->m_apPlayers[i]->KillCharacter(WEAPON_GAME);
+
+ char chat_msg[128];
+ str_format (chat_msg, sizeof (chat_msg), "%s was caught camping near a goal...",
+ Server()->ClientName(GameServer()->m_apPlayers[i]->m_ClientID));
+ GameServer()->SendChat(-1, -2, chat_msg);
+ continue;
+ }
+ }
+ }
+
+ // anti-camping
+ if (g_Config.m_SvfbCampMaxtime)
+ {
+ if (distance (ch->m_Pos, ch->m_CampPos) <= g_Config.m_SvfbCampThreshold && !ch->m_pBall)
+ {
+ // if in range, count up 2 ticks
+ ch->m_CampTick += 2;
+ }
+ else
+ {
+ // if out of range, count down just 1 tick again (slower)
+ if (ch->m_CampTick)
+ ch->m_CampTick--;
+ else
+ ch->m_CampPos = ch->m_Pos;
+ }
+
+ // kill camping player
+ if ((ch->m_CampTick >> 1) >= Server()->TickSpeed () * g_Config.m_SvfbCampMaxtime)
+ {
+ GameServer()->m_apPlayers[i]->KillCharacter(WEAPON_GAME);
+ GameServer()->SendChat(-1, -2, "I'm a bloody camper");
+ continue;
+ }
+ }
+ }
+
+ // update balls
+ for (int bi = 0; bi < FB_MAX_BALLS; ++bi)
+ {
+ CBall *b = m_apBalls[bi];
+
+ if (!b)
+ continue;
+
+ // update position here and not in CBall::Tick because balls tend to tick before characters
+ if (b->m_pCarryingCharacter)
+ b->m_Pos = b->m_pCarryingCharacter->m_Pos;
+
+ // check/handle goal
+ bool is_goal = false;
+ for (int g = 0; g < m_NumGoals; g++)
+ {
+ if (distance(b->m_Pos, m_apGoalPos[g]) < g_Config.m_SvfbGoalsize)
+ {
+ is_goal = HandleGoal(b, g);
+ break;
+ }
+ }
+ if (is_goal)
+ continue;
+
+ if (b->m_pCarryingCharacter)
+ { // ball is carried by player
+ // warn ball-carrying player once when he is near his own goal
+ CCharacter *ch = b->m_pCarryingCharacter;
+ CPlayer *p = ch->GetPlayer();
+ int t = p->GetTeam();
+ if (g_Config.m_SvfbOwngoalWarn && !p->m_OwngoalWarned && t < m_NumGoals && distance(ch->m_Pos, m_apGoalPos[t]) < g_Config.m_SvfbGoalsize * 5)
+ {
+ GameServer()->SendBroadcast(
+ "Attention! This is your team's goal\n"
+ "you are approaching. You probably\n"
+ "want to go to the other side!",
+ p->m_ClientID);
+
+ // play the server-chat sound
+ GameServer()->CreateSound(ch->m_Pos, SOUND_CHAT_SERVER, CmaskOne(p->m_ClientID));
+ p->m_OwngoalWarned = true;
+ }
+ }
+ else
+ { // ball is carried by none
+ // small delay for throwing ball a bit away before fetching again
+ if (b->m_AtStand || Server()->Tick() >= b->m_DropTick + Server()->TickSpeed() * 0.2f)
+ {
+ // find all players that can grab the ball
+ CCharacter *close_characters[MAX_CLIENTS];
+ int max_num = GameServer()->m_World.FindEntities(b->m_Pos, b->ms_PhysSize, (CEntity**)close_characters, MAX_CLIENTS, CGameWorld::ENTTYPE_CHARACTER);
+ int curr_num = 0;
+ for (int i = 0; i < max_num; ++i)
+ {
+ if (!close_characters[i]->IsAlive() || close_characters[i]->GetPlayer()->GetTeam() == -1 || GameServer()->Collision()->IntersectLine(b->m_Pos, close_characters[i]->m_Pos, NULL, NULL) ||
+ // don't take flag if already have one (might be useful with two flags)
+ m_apBalls[bi ^ 1]->m_pCarryingCharacter == close_characters[i])
+ continue;
+ close_characters[curr_num++] = close_characters[i];
+ }
+
+ if (!curr_num)
+ continue;
+
+ GrantBall(close_characters[Server()->Tick() % curr_num], b);
+ }
+ }
+ }
+ }
+}
+
+void CGameControllerFB::Snap(int SnappingClient)
+{
+
+ IGameController::Snap(SnappingClient);
+
+ CNetObj_GameData *pGameDataObj = (CNetObj_GameData *)Server()->SnapNewItem(NETOBJTYPE_GAMEDATA, 0, sizeof(CNetObj_GameData));
+ if(!pGameDataObj)
+ return;
+
+ pGameDataObj->m_TeamscoreRed = m_aTeamscore[TEAM_RED];
+ pGameDataObj->m_TeamscoreBlue = m_aTeamscore[TEAM_BLUE];
+
+ if(m_apBalls[TEAM_RED])
+ {
+ if(m_apBalls[TEAM_RED]->m_AtStand)
+ {
+ pGameDataObj->m_FlagCarrierRed = FLAG_ATSTAND;
+ }
+ else if(m_apBalls[TEAM_RED]->m_pCarryingCharacter)
+ {
+ pGameDataObj->m_FlagCarrierRed = m_apBalls[TEAM_RED]->m_pCarryingCharacter->GetPlayer()->GetCID();
+ }
+ else
+ {
+ pGameDataObj->m_FlagCarrierRed = FLAG_TAKEN;
+ }
+ }
+ else
+ {
+ pGameDataObj->m_FlagCarrierRed = FLAG_MISSING;
+ }
+
+ if(m_apBalls[TEAM_BLUE])
+ {
+ if(m_apBalls[TEAM_BLUE]->m_AtStand)
+ {
+ pGameDataObj->m_FlagCarrierBlue = FLAG_ATSTAND;
+ }
+ else if(m_apBalls[TEAM_BLUE]->m_pCarryingCharacter)
+ {
+ pGameDataObj->m_FlagCarrierBlue = m_apBalls[TEAM_BLUE]->m_pCarryingCharacter->GetPlayer()->GetCID();
+ }
+ else
+ {
+ pGameDataObj->m_FlagCarrierBlue = FLAG_TAKEN;
+ }
+ }
+ else
+ {
+ pGameDataObj->m_FlagCarrierBlue = FLAG_MISSING;
+ }
+}
+
+bool CGameControllerFB::CanSpawn(int Team, vec2 *pOutPos)
+{
+ CSpawnEval Eval;
+
+ // spectators can't spawn
+ if(Team == TEAM_SPECTATORS)
+ return false;
+
+ Eval.m_FriendlyTeam = Team;
+
+ // try own team only
+ EvaluateSpawnType(&Eval, 1+(Team&1));
+
+ // try harder
+ if(!Eval.m_Got)
+ FindFreeSpawn(&Eval, 1+(Team&1));
+
+ *pOutPos = Eval.m_Pos;
+ return Eval.m_Got;
+}
diff --git a/src/game/server/gamemodes/fb.h b/src/game/server/gamemodes/fb.h
new file mode 100644
index 0000000..4979314
--- /dev/null
+++ b/src/game/server/gamemodes/fb.h
@@ -0,0 +1,47 @@
+#ifndef GAME_SERVER_GAMEMODES_FB_H
+#define GAME_SERVER_GAMEMODES_FB_H
+
+#include
+#include
+
+enum {
+ FB_MAX_GOALS = 2,
+ FB_MAX_BALLS = 2
+};
+
+class CBall: public CFlag
+{
+public:
+ CPlayer* m_pLastCarrier;
+ int m_LastCarrierTeam;
+ int m_IdleTick;
+
+ CBall(CGameWorld *pGameWorld, int Team, vec2 Pos);
+
+ virtual void Reset();
+ virtual void Tick();
+};
+
+class CGameControllerFB : public IGameController
+{
+public:
+ class CBall *m_apBalls[FB_MAX_BALLS];
+ vec2 m_apGoalPos[FB_MAX_GOALS];
+ int m_NumGoals;
+
+ CGameControllerFB(class CGameContext *pGameServer);
+ virtual void Tick();
+
+ virtual bool OnEntity (int index, vec2 pos);
+ virtual int OnCharacterDeath (class CCharacter *victim, class CPlayer *killer, int weapon);
+ virtual void OnCharacterSpawn (class CCharacter *chr);
+ virtual void CreateBallGrabSound(int team);
+ virtual void GrantBall(CCharacter *, CBall *);
+ virtual void SetBallColor(CBall *&, int team);
+ virtual bool HandleGoal (CBall *, int goal);
+ virtual void OnDisconnect (CPlayer *const p);
+ virtual void Snap(int SnappingClient);
+ virtual bool CanSpawn(int Team, vec2 *pOutPos);
+};
+
+#endif
diff --git a/src/game/server/gameworld.cpp b/src/game/server/gameworld.cpp
index 8fffabc..4c74ad6 100644
--- a/src/game/server/gameworld.cpp
+++ b/src/game/server/gameworld.cpp
@@ -104,6 +104,7 @@ void CGameWorld::RemoveEntity(CEntity *pEnt)
//
void CGameWorld::Snap(int SnappingClient)
{
+
for(int i = 0; i < NUM_ENTTYPES; i++)
for(CEntity *pEnt = m_apFirstEntityTypes[i]; pEnt; )
{
@@ -149,6 +150,7 @@ void CGameWorld::RemoveEntities()
void CGameWorld::Tick()
{
+
if(m_ResetRequested)
Reset();
diff --git a/src/game/server/maprotation.cpp b/src/game/server/maprotation.cpp
new file mode 100644
index 0000000..8454d23
--- /dev/null
+++ b/src/game/server/maprotation.cpp
@@ -0,0 +1,123 @@
+#include "maprotation.h"
+
+#include
+#include
+#include
+
+#include
+#include
+#include
+#include
+#include
+
+#include
+#include
+
+class CRandomMapRotation: public IMapRotation
+{
+public:
+ class CMap
+ {
+ public:
+ const char* m_pName;
+ float m_Probability;
+
+ CMap(const char* name, float weight);
+ };
+ std::vector m_MapList;
+ const char* m_pMapFile;
+ time_t m_MapFileMTime;
+
+ CRandomMapRotation();
+
+ virtual const char* NextMap(const char* rotation, const char* current);
+ void UpdateList(const char* rotation);
+ void ClearList();
+};
+
+time_t GetMTime(const char* file)
+{
+ struct stat st;
+ if (stat(file, &st) < 0)
+ {
+ dbg_msg("rotation", "Cannot stat %s: %s", file, strerror(errno));
+ return -1;
+ }
+ return st.st_mtime;
+}
+
+CRandomMapRotation::CMap::CMap(const char* name, float probability)
+: m_pName(name), m_Probability(probability) {}
+
+CRandomMapRotation::CRandomMapRotation()
+: m_pMapFile(NULL) {};
+
+void CRandomMapRotation::UpdateList(const char* rotation)
+{
+ if (m_pMapFile && str_comp(rotation, m_pMapFile) == 0)
+ {
+ time_t mtime = GetMTime(m_pMapFile);
+ if (mtime < 0 || mtime == m_MapFileMTime)
+ return;
+ m_MapFileMTime = mtime;
+ }
+ else
+ {
+ time_t mtime = GetMTime(rotation);
+ if (mtime < 0) return;
+ m_pMapFile = rotation;
+ m_MapFileMTime = mtime;
+ }
+
+ ClearList();
+
+ std::ifstream f(m_pMapFile);
+ while (1)
+ {
+ char buf[128];
+ float weight;
+ f >> buf >> weight;
+ if (!f) break;
+ char *name = new char[strlen(buf) + 1];
+ if (!name) break;
+ strcpy(name, buf);
+ m_MapList.push_back(CMap(name, weight));
+ }
+
+ // normalize probabilities
+ float norm = 0;
+ for (std::vector::const_iterator m = m_MapList.begin(); m != m_MapList.end(); ++m)
+ norm += m->m_Probability;
+ for (std::vector::iterator m = m_MapList.begin(); m != m_MapList.end(); ++m)
+ m->m_Probability /= norm;
+
+ for (std::vector::const_iterator m = m_MapList.begin(); m != m_MapList.end(); ++m)
+ dbg_msg("rotation", "registering map %s with probability %g", m->m_pName, m->m_Probability);
+}
+
+void CRandomMapRotation::ClearList()
+{
+ for (std::vector::const_iterator m = m_MapList.begin(); m != m_MapList.end(); ++m)
+ delete[] m->m_pName;
+ m_MapList.clear();
+}
+
+const char* CRandomMapRotation::NextMap(const char* rotation, const char* current)
+{
+ UpdateList(rotation);
+ if (m_MapList.empty()) return current;
+ float w = frandom();
+ float x = 0;
+ for (std::vector::const_iterator m = m_MapList.begin(); m != m_MapList.end(); ++m)
+ {
+ x += m->m_Probability;
+ if (x >= w) return m->m_pName;
+ }
+ // should never happen
+ return current;
+}
+
+IMapRotation *RandomMapRotation()
+{
+ return new CRandomMapRotation;
+}
diff --git a/src/game/server/maprotation.h b/src/game/server/maprotation.h
new file mode 100644
index 0000000..d589b2d
--- /dev/null
+++ b/src/game/server/maprotation.h
@@ -0,0 +1,12 @@
+#ifndef GAME_SERVER_MAPROTATION_H
+#define GAME_SERVER_MAPROTATION_H
+
+class IMapRotation {
+ public:
+ virtual const char* NextMap(const char* rotation, const char* current) = 0;
+ virtual ~IMapRotation() {};
+};
+
+IMapRotation *RandomMapRotation();
+
+#endif
diff --git a/src/game/server/player.cpp b/src/game/server/player.cpp
index cf0e668..770a426 100644
--- a/src/game/server/player.cpp
+++ b/src/game/server/player.cpp
@@ -4,6 +4,9 @@
#include
#include "player.h"
+#include
+#include "gamemodes/fb.h"
+
MACRO_ALLOC_POOL_ID_IMPL(CPlayer, MAX_CLIENTS)
@@ -17,6 +20,10 @@ CPlayer::CPlayer(CGameContext *pGameServer, int ClientID, int Team)
m_ScoreStartTick = Server()->Tick();
Character = 0;
this->m_ClientID = ClientID;
+
+ m_NumOwngoals = 0;
+ m_OwngoalWarned = false;
+
m_Team = GameServer()->m_pController->ClampTeam(Team);
m_SpectatorID = SPEC_FREEVIEW;
m_LastActionTick = Server()->Tick();
@@ -146,6 +153,11 @@ void CPlayer::OnDisconnect(const char *pReason)
if(Server()->ClientIngame(m_ClientID))
{
+ // update leaving player in gamecontroller (flagball)
+ if (str_comp(GameServer()->m_pController->m_pGameType, "FB")==0)
+ {
+ static_cast (GameServer()->m_pController)->OnDisconnect(this);
+ }
char aBuf[512];
if(pReason && *pReason)
str_format(aBuf, sizeof(aBuf), "'%s' has left the game (%s)", Server()->ClientName(m_ClientID), pReason);
@@ -233,6 +245,9 @@ void CPlayer::SetTeam(int Team)
GameServer()->m_pController->OnPlayerInfoChange(GameServer()->m_apPlayers[m_ClientID]);
+ //update active player (idle kicking)
+ m_LastActionTick = Server()->Tick();
+
if(Team == TEAM_SPECTATORS)
{
// update spectator modes
diff --git a/src/game/server/player.h b/src/game/server/player.h
index 50f1c1a..c9c1dcb 100644
--- a/src/game/server/player.h
+++ b/src/game/server/player.h
@@ -32,6 +32,10 @@ public:
void OnPredictedInput(CNetObj_PlayerInput *NewInput);
void OnDisconnect(const char *pReason);
+ // flagball
+ int m_NumOwngoals; // counter for own-goals
+ bool m_OwngoalWarned; // own goal warning (only shown once)
+
void KillCharacter(int Weapon = WEAPON_GAME);
CCharacter *GetCharacter();
@@ -95,16 +99,16 @@ public:
int m_Max;
} m_Latency;
-private:
+
+//private:
CCharacter *Character;
CGameContext *m_pGameServer;
-
+ int m_ClientID;
CGameContext *GameServer() const { return m_pGameServer; }
IServer *Server() const;
//
bool m_Spawning;
- int m_ClientID;
int m_Team;
};
diff --git a/src/game/variables.h b/src/game/variables.h
index c4a37fa..ce9695c 100644
--- a/src/game/variables.h
+++ b/src/game/variables.h
@@ -60,9 +60,9 @@ MACRO_CONFIG_INT(SvTeamdamage, sv_teamdamage, 0, 0, 1, CFGFLAG_SERVER, "Team dam
MACRO_CONFIG_STR(SvMaprotation, sv_maprotation, 768, "", CFGFLAG_SERVER, "Maps to rotate between")
MACRO_CONFIG_INT(SvRoundsPerMap, sv_rounds_per_map, 1, 1, 100, CFGFLAG_SERVER, "Number of rounds on each map before rotating")
MACRO_CONFIG_INT(SvPowerups, sv_powerups, 1, 0, 1, CFGFLAG_SERVER, "Allow powerups like ninja")
-MACRO_CONFIG_INT(SvScorelimit, sv_scorelimit, 20, 0, 1000, CFGFLAG_SERVER, "Score limit (0 disables)")
-MACRO_CONFIG_INT(SvTimelimit, sv_timelimit, 0, 0, 1000, CFGFLAG_SERVER, "Time limit in minutes (0 disables)")
-MACRO_CONFIG_STR(SvGametype, sv_gametype, 32, "dm", CFGFLAG_SERVER, "Game type (dm, tdm, ctf)")
+MACRO_CONFIG_INT(SvScorelimit, sv_scorelimit, 20, 0, 1000, CFGFLAG_SERVER, "Score limit")
+MACRO_CONFIG_INT(SvTimelimit, sv_timelimit, 0, 0, 1000, CFGFLAG_SERVER, "Time limit in minutes")
+MACRO_CONFIG_STR(SvGametype, sv_gametype, 32, "fb", CFGFLAG_SERVER, "Game type (dm, tdm, ctf, fb, ifb)")
MACRO_CONFIG_INT(SvTournamentMode, sv_tournament_mode, 0, 0, 1, CFGFLAG_SERVER, "Tournament mode. When enabled, players joins the server as spectator")
MACRO_CONFIG_INT(SvSpamprotection, sv_spamprotection, 1, 0, 1, CFGFLAG_SERVER, "Spam protection")
@@ -78,6 +78,37 @@ MACRO_CONFIG_INT(SvVoteKick, sv_vote_kick, 1, 0, 1, CFGFLAG_SERVER, "Allow votin
MACRO_CONFIG_INT(SvVoteKickMin, sv_vote_kick_min, 0, 0, MAX_CLIENTS, CFGFLAG_SERVER, "Minimum number of players required to start a kick vote")
MACRO_CONFIG_INT(SvVoteKickBantime, sv_vote_kick_bantime, 5, 0, 1440, CFGFLAG_SERVER, "The time to ban a player if kicked by vote. 0 makes it just use kick")
+/* flagball */
+MACRO_CONFIG_INT(SvfbBallDamageLose, sv_fb_ball_damage_lose, 1, 0, 1, CFGFLAG_SERVER, "Lose ball on any damage")
+MACRO_CONFIG_INT(SvfbBallResetTime, sv_fb_ball_reset_time, 30, 1, 500, CFGFLAG_SERVER, "Number of seconds needed to reset a lying ball")
+MACRO_CONFIG_INT(SvfbBallVelocity, sv_fb_ball_velocity, 207, 10, 3000, CFGFLAG_SERVER, "Velocity of the ball after it got shot")
+MACRO_CONFIG_INT(SvfbCampMaxtime, sv_fb_camp_maxtime, 0, 0, 100, CFGFLAG_SERVER, "Number of seconds allowed lingering at the same place")
+MACRO_CONFIG_INT(SvfbCampThreshold, sv_fb_camp_threshold, 200, 64, 1000, CFGFLAG_SERVER, "Threshold for anti-camp distance")
+MACRO_CONFIG_INT(SvfbDirectPass, sv_fb_direct_pass, 1, 0, 1, CFGFLAG_SERVER, "Let players pass ball with hook")
+MACRO_CONFIG_INT(SvfbBallOffsetX, sv_fb_ball_offset_x, 0, 0, 1000, CFGFLAG_SERVER, "X offset of the hookable center of the ball with respect to the lower left corner of the image")
+MACRO_CONFIG_INT(SvfbBallOffsetY, sv_fb_ball_offset_y, 38, 0, 1000, CFGFLAG_SERVER, "Y offset of the hookable center of the ball with respect to the lower left corner of the image")
+MACRO_CONFIG_INT(SvfbBallRadius, sv_fb_ball_radius, 40, 0, 1000, CFGFLAG_SERVER, "Flag hookable radius")
+MACRO_CONFIG_INT(SvfbLaserMomentum, sv_fb_laser_momentum, 207, -3000, 3000, CFGFLAG_SERVER, "Momentum passed to a flag when it is hit by laser")
+MACRO_CONFIG_INT(SvfbGoalsize, sv_fb_goalsize, 64, 32, 500, CFGFLAG_SERVER, "Radius defining goal")
+MACRO_CONFIG_INT(SvfbGoalcamp, sv_fb_goalcamp, 1, 0, 1, CFGFLAG_SERVER, "Activate goal camp protection")
+MACRO_CONFIG_INT(SvfbGoalcampTime, sv_fb_goalcamp_time, 3, 1, 600, CFGFLAG_SERVER, "Number of seconds allowed lingering near a goal")
+MACRO_CONFIG_INT(SvfbGoalcampFactor, sv_fb_goalcamp_factor, 40, 10, 100, CFGFLAG_SERVER, "Goal camp protection radius")
+MACRO_CONFIG_INT(SvfbHookBall, sv_fb_hook_ball, 1, 0, 1, CFGFLAG_SERVER, "Make the ball hookable")
+MACRO_CONFIG_INT(SvfbInstagib, sv_fb_instagib, 1, 0, 1, CFGFLAG_SERVER, "Activate instagib")
+MACRO_CONFIG_INT(SvfbOwngoal, sv_fb_owngoal, 0, 0, 1, CFGFLAG_SERVER, "Allow own goals")
+MACRO_CONFIG_INT(SvfbOwngoalKick, sv_fb_owngoal_kick, 2, 0, 20, CFGFLAG_SERVER, "Number of own goals allowed before kicking the player")
+MACRO_CONFIG_INT(SvfbOwngoalPenalty, sv_fb_owngoal_penalty, 30, 0, 999, CFGFLAG_SERVER, "Negative score for own goal player")
+MACRO_CONFIG_INT(SvfbOwngoalWarn, sv_fb_owngoal_warn, 0, 0, 1, CFGFLAG_SERVER, "Warn when player with ball is near own goal")
+MACRO_CONFIG_INT(SvfbScorePlayerBall, sv_fb_score_player_ball, 5, 0, 100, CFGFLAG_SERVER, "Player score for ball goal")
+MACRO_CONFIG_INT(SvfbScorePlayerStand, sv_fb_score_player_stand, 0, 0, 10, CFGFLAG_SERVER, "Player score for taking ball from stand")
+MACRO_CONFIG_INT(SvfbScorePlayerTee, sv_fb_score_player_tee, 10, 0, 100, CFGFLAG_SERVER, "Player score for tee goal")
+MACRO_CONFIG_INT(SvfbScoreTeamBall, sv_fb_score_team_ball, 50, 1, 100, CFGFLAG_SERVER, "Team score for ball goal")
+MACRO_CONFIG_INT(SvfbScoreTeamStand, sv_fb_score_team_stand, 0, 0, 10, CFGFLAG_SERVER, "Team score for taking ball from stand")
+MACRO_CONFIG_INT(SvfbScoreTeamTee, sv_fb_score_team_tee, 100, 1, 100, CFGFLAG_SERVER, "Team score for tee goal")
+MACRO_CONFIG_STR(SvfbWelcomeMessage, sv_fb_welcome_message, 512, "", CFGFLAG_SERVER, "Message to display when clients join")
+MACRO_CONFIG_INT(SvfbSelfKill, sv_fb_self_kill, 0, 0, 1, CFGFLAG_SERVER, "Allow self kill")
+MACRO_CONFIG_INT(SvfbSpawnWeaponDischarge, sv_fb_spawn_weapon_discharge, 50, 0, 100, CFGFLAG_SERVER, "Amount of time players cannot fire after respawn (in percents of laser reloading time)")
+
// debug
#ifdef CONF_DEBUG // this one can crash the server if not used correctly
MACRO_CONFIG_INT(DbgDummies, dbg_dummies, 0, 0, 15, CFGFLAG_SERVER, "")
diff --git a/src/game/version.h b/src/game/version.h
index 2cd5e7e..f8f4c50 100644
--- a/src/game/version.h
+++ b/src/game/version.h
@@ -3,6 +3,8 @@
#ifndef GAME_VERSION_H
#define GAME_VERSION_H
#include "generated/nethash.c"
-#define GAME_VERSION "0.6.0"
+#define GAME_VERSION "0.6 trunk"
#define GAME_NETVERSION "0.6 " GAME_NETVERSION_HASH
+/* FlagBall-MOD version */
+#define MOD_VERSION "0.2.0"
#endif