Release 0.1.11-alpha: Merge branch 'dev'

1008-fix
krzys-h 2017-11-10 11:01:24 +01:00
commit b143aa38ac
57 changed files with 1324 additions and 410 deletions

View File

@ -16,9 +16,9 @@ set(COLOBOT_VERSION_MINOR 1)
set(COLOBOT_VERSION_REVISION 10)
# Used on official releases
set(COLOBOT_VERSION_RELEASE_CODENAME "-alpha")
#set(COLOBOT_VERSION_RELEASE_CODENAME "-alpha")
# Used on unreleased, development builds
#set(COLOBOT_VERSION_UNRELEASED "+alpha")
set(COLOBOT_VERSION_UNRELEASED "+alpha")
# Append git characteristics to version
if(DEFINED COLOBOT_VERSION_UNRELEASED)

2
data

@ -1 +1 @@
Subproject commit f4c4364f00afe2a754204dec387cd80124b15c3a
Subproject commit 928d03d15c1e506d3e3a81513c4a2f8607ce2bf6

View File

@ -516,25 +516,19 @@ msgstr ""
msgid "Origin of last message\\Shows where the last message was sent from"
msgstr ""
msgid "Speed 0.5x\\Half speed"
msgid "Lower speed\\Decrease speed by half"
msgstr ""
msgid "Speed 1.0x\\Normal speed"
msgid "Standard speed\\Reset speed to normal"
msgstr ""
msgid "Speed 1.5x\\1.5 times faster"
msgid "Higher speed\\Doubles speed"
msgstr ""
msgid "Speed 2.0x\\Double speed"
msgid "Quick save\\Immediately save game"
msgstr ""
msgid "Speed 3.0x\\Triple speed"
msgstr ""
msgid "Speed 4.0x\\Quadruple speed"
msgstr ""
msgid "Speed 6.0x\\Sextuple speed"
msgid "Quick load\\Immediately load game"
msgstr ""
msgid "Pause\\Pause the game without opening menu"
@ -1533,6 +1527,9 @@ msgstr ""
msgid "Inappropriate bot"
msgstr ""
msgid "Quicksave slot not found"
msgstr ""
msgid "Building completed"
msgstr ""
@ -1773,6 +1770,24 @@ msgstr ""
msgid "This parameter needs a default value"
msgstr ""
msgid "Missing end quote"
msgstr ""
msgid "Unknown escape sequence"
msgstr ""
msgid "Octal value out of range"
msgstr ""
msgid "Missing hex digits after escape sequence"
msgstr ""
msgid "Hex value out of range"
msgstr ""
msgid "Invalid universal character name"
msgstr ""
msgid "Dividing by zero"
msgstr ""

134
po/de.po
View File

@ -100,9 +100,7 @@ msgid "Already carrying something"
msgstr "Trägt schon etwas"
msgid "Alternative camera mode\\Move sideways instead of rotating (in free camera)"
msgstr ""
"Alternativer Kameramodus\\Seitwärts bewegen statt rotieren (bei freier "
"Kamera)"
msgstr "Alternativer Kameramodus\\Seitwärts bewegen statt rotieren (bei freier Kamera)"
msgid "Ambiguous call to overloaded function"
msgstr ""
@ -144,14 +142,10 @@ msgid "Automatic indent\\When program editing"
msgstr "Automatisches Einrücken\\Beim Bearbeiten der Programme"
msgid "Autosave interval\\How often your game will autosave"
msgstr ""
"Auto-Speichern Zeitintervall\\Wie oft das Spiel automatisch abgespeichert "
"wird"
msgstr "Auto-Speichern Zeitintervall\\Wie oft das Spiel automatisch abgespeichert wird"
msgid "Autosave slots\\How many autosave slots you'll have"
msgstr ""
"Auto-Speicherplätze\\Wie viele Plätze zum automatischen Speichern zur "
"Verfügung stehen"
msgstr "Auto-Speicherplätze\\Wie viele Plätze zum automatischen Speichern zur Verfügung stehen"
msgid "Autosave\\Enables autosave"
msgstr "Auto-Speichern\\Aktiviert die automatische Speicherung"
@ -316,9 +310,7 @@ msgid "Camera back\\Moves the camera backward"
msgstr "Kamera weiter\\Bewegung der Kamera rückwärts"
msgid "Camera border scrolling\\Scrolling when the mouse touches right or left border"
msgstr ""
"Kamerabewegung am Bildschirmrand\\Die Kamera dreht wenn die Maus den rechten "
"oder linken Rand erreicht"
msgstr "Kamerabewegung am Bildschirmrand\\Die Kamera dreht wenn die Maus den rechten oder linken Rand erreicht"
msgid "Camera closer\\Moves the camera forward"
msgstr "Kamera näher\\Bewegung der Kamera vorwärts"
@ -688,6 +680,13 @@ msgstr "Anweisungen über das ausgewählte Objekt"
msgid "Help balloons\\Explain the function of the buttons"
msgstr "Hilfeblasen\\Hilfeblasen"
msgid "Hex value out of range"
msgstr ""
#, fuzzy
msgid "Higher speed\\Doubles speed"
msgstr "Geschwindigkeit 2.0x\\Spielgeschwindigkeit doppelt so schnell"
msgid "Highest\\Highest graphic quality (lowest frame rate)"
msgstr "Max.\\Beste Qualität (niedriges Framerate)"
@ -763,6 +762,9 @@ msgstr "Anweisungen\\Anweisungen für die Mission oder Übung"
msgid "Internal error - tell the developers"
msgstr "Interner Fehler - Benachrichtige bitte die Entwickler"
msgid "Invalid universal character name"
msgstr ""
msgid "Invert\\Invert values on this axis"
msgstr "Invertieren\\Die Werte dieser Achse invertieren"
@ -838,6 +840,23 @@ msgstr "Lade Objekte"
msgid "Loading terrain"
msgstr "Lade Gelände"
# msgid "Speed 0.5x\\Half speed"
# msgstr ""
# msgid "Speed 1.0x\\Normal speed"
# msgstr ""
# msgid "Speed 1.5x\\1.5 times faster"
# msgstr ""
# msgid "Speed 2.0x\\Double speed"
# msgstr ""
# msgid "Speed 3.0x\\Triple speed"
# msgstr ""
# msgid "Speed 4.0x\\Quadruple speed"
# msgstr ""
# msgid "Speed 6.0x\\Sextuple speed"
# msgstr ""
msgid "Lower speed\\Decrease speed by half"
msgstr ""
msgid "Lowest\\Minimum graphic quality (highest frame rate)"
msgstr "Min.\\Minimale Qualität (großes Framerate)"
@ -856,6 +875,12 @@ msgstr "Verkleinern"
msgid "Mipmap level\\Mipmap level"
msgstr "Mipmap-Level\\Mipmap-Level"
msgid "Missing end quote"
msgstr ""
msgid "Missing hex digits after escape sequence"
msgstr ""
msgid "Mission name"
msgstr "Name der Mission"
@ -1018,6 +1043,9 @@ msgstr "OK\\Programm kompilieren"
msgid "Object too close"
msgstr "Gegenstand zu nahe"
msgid "Octal value out of range"
msgstr ""
msgid "One step"
msgstr "Ein Schritt"
@ -1064,9 +1092,7 @@ msgid "Pause blur\\Blur the background on the pause screen"
msgstr "Pausen-Unschärfe\\Während der Pause den Hintergrund unscharf zeichnen"
msgid "Pause in background\\Pause the game when the window is unfocused"
msgstr ""
"Pausieren im Hintergrund\\Spiel anhalten,enn das Spielfenster im Hintergrund "
"ist"
msgstr "Pausieren im Hintergrund\\Spiel anhalten,enn das Spielfenster im Hintergrund ist"
msgid "Pause/continue"
msgstr "Pause/Weitermachen"
@ -1194,6 +1220,16 @@ msgstr "Öffentlich\\Gemeinsamer Ordner für alle Spieler"
msgid "Quake at explosions\\The screen shakes at explosions"
msgstr "Beben bei Explosionen\\Die Kamera bebt bei Explosionen"
msgid "Quick load\\Immediately load game"
msgstr ""
msgid "Quick save\\Immediately save game"
msgstr ""
#, fuzzy
msgid "Quicksave slot not found"
msgstr "Das Objekt existiert nicht"
msgid "Quit\\Quit Colobot: Gold Edition"
msgstr "Beenden\\Colobot: Gold Edition schließen"
@ -1404,27 +1440,6 @@ msgstr "Raumschiff"
msgid "Spaceship ruin"
msgstr "Raumschiffswrack"
msgid "Speed 0.5x\\Half speed"
msgstr "Geschwindigkeit 0.5x\\Halbe Spielgeschwindigkeit"
msgid "Speed 1.0x\\Normal speed"
msgstr "Geschwindigkeit 1.0x\\Normale Spielgeschwindigkeit"
msgid "Speed 1.5x\\1.5 times faster"
msgstr "Geschwindigkeit 1.5x\\Spielgeschwindigkeit anderthalb Mal schneller"
msgid "Speed 2.0x\\Double speed"
msgstr "Geschwindigkeit 2.0x\\Spielgeschwindigkeit doppelt so schnell"
msgid "Speed 3.0x\\Triple speed"
msgstr "Geschwindigkeit 3.0x\\Dreifache Spielgeschwindigkeit"
msgid "Speed 4.0x\\Quadruple speed"
msgstr "Geschwindigkeit 4.0x\\Vierfache Spielgeschwindigkeit"
msgid "Speed 6.0x\\Sextuple speed"
msgstr "Geschwindigkeit 6.0x\\Sechsfache Spielgeschwindigkeit"
msgid "Spider"
msgstr "Spinne"
@ -1440,6 +1455,9 @@ msgstr "Standardhandlung\\Führt die Standardhandlung des Roboters aus"
msgid "Standard controls\\Standard key functions"
msgstr "Alles zurücksetzen\\Standarddefinition aller Tasten"
msgid "Standard speed\\Reset speed to normal"
msgstr ""
msgid "Standard\\Standard appearance settings"
msgstr "Standard\\Standardfarben einsetzen"
@ -1525,9 +1543,7 @@ msgid "This label does not exist"
msgstr "Dieses Label existiert nicht"
msgid "This menu is for userlevels from mods, but you didn't install any"
msgstr ""
"Dieses Menü ist für nachinstallierte Benutzer-Level, aber Du hast keine "
"installiert"
msgstr "Dieses Menü ist für nachinstallierte Benutzer-Level, aber Du hast keine installiert"
msgid "This object is currently busy"
msgstr ""
@ -1631,6 +1647,9 @@ msgstr "Das Objekt existiert nicht"
msgid "Unknown command"
msgstr "Befehl unbekannt"
msgid "Unknown escape sequence"
msgstr ""
msgid "Unknown function"
msgstr "Unbekannte Funktion"
@ -1740,22 +1759,14 @@ msgstr "Sie haben ein brauchbares Objekt gefunden"
#, c-format
msgid "You have to use \"%1$s\" at least once in this exercise (used: %2$d)"
msgid_plural "You have to use \"%1$s\" at least %3$d times in this exercise (used: %2$d)"
msgstr[0] ""
"In dieser Übung \"%1$s\" muß mindestens einmal verwendet werden (benutzt: %"
"2$d)"
msgstr[1] ""
"In dieser Übung muß \"%1$s\" mindestes %3$d Mal verwendet werden (benutzt: %"
"2$d)"
msgstr[0] "In dieser Übung \"%1$s\" muß mindestens einmal verwendet werden (benutzt: %2$d)"
msgstr[1] "In dieser Übung muß \"%1$s\" mindestes %3$d Mal verwendet werden (benutzt: %2$d)"
#, c-format
msgid "You have to use \"%1$s\" at most once in this exercise (used: %2$d)"
msgid_plural "You have to use \"%1$s\" at most %3$d times in this exercise (used: %2$d)"
msgstr[0] ""
"In dieser Übung darf \"%1$s\" höchstens einmal verwendet werden (benutzt: %"
"2$d)"
msgstr[1] ""
"In dieser Übung darf \"%1$s\" höchstens %3$d Mal verwendet werden (benutzt: %"
"2$d)"
msgstr[0] "In dieser Übung darf \"%1$s\" höchstens einmal verwendet werden (benutzt: %2$d)"
msgstr[1] "In dieser Übung darf \"%1$s\" höchstens %3$d Mal verwendet werden (benutzt: %2$d)"
msgid "You must get on the spaceship to take off"
msgstr "Begib Dich an Bord, bevor Du abhebst"
@ -1950,9 +1961,6 @@ msgstr "epsitec.com"
#~ msgid "Num of decorative objects\\Number of purely ornamental objects"
#~ msgstr "Anzahl Ziergegenstände\\Anzahl Gegenstände ohne Funktion"
#~ msgid "Object not found"
#~ msgstr "Das Objekt existiert nicht"
#~ msgid "Planets and stars\\Astronomical objects in the sky"
#~ msgstr "Planeten und Sterne\\Kreisende Planeten und Sterne"
@ -1968,9 +1976,27 @@ msgstr "epsitec.com"
#~ msgid "Sky\\Clouds and nebulae"
#~ msgstr "Himmel\\Himmel und Wolken"
#~ msgid "Speed 0.5x\\Half speed"
#~ msgstr "Geschwindigkeit 0.5x\\Halbe Spielgeschwindigkeit"
#~ msgid "Speed 1.0x\\Normal speed"
#~ msgstr "Geschwindigkeit 1.0x\\Normale Spielgeschwindigkeit"
#~ msgid "Speed 1.5x\\1.5 times faster"
#~ msgstr "Geschwindigkeit 1.5x\\Spielgeschwindigkeit anderthalb Mal schneller"
#~ msgid "Speed 3.0x\\Three times faster"
#~ msgstr "Geschwindigkeit 3.0x\\Spielgeschwindigkeit drei Mal schneller"
#~ msgid "Speed 3.0x\\Triple speed"
#~ msgstr "Geschwindigkeit 3.0x\\Dreifache Spielgeschwindigkeit"
#~ msgid "Speed 4.0x\\Quadruple speed"
#~ msgstr "Geschwindigkeit 4.0x\\Vierfache Spielgeschwindigkeit"
#~ msgid "Speed 6.0x\\Sextuple speed"
#~ msgstr "Geschwindigkeit 6.0x\\Sechsfache Spielgeschwindigkeit"
#~ msgid "Sunbeams\\Sunbeams in the sky"
#~ msgstr "Sonnenstrahlen\\Sonnenstrahlen"

View File

@ -677,6 +677,13 @@ msgstr "Instructions sur la sélection"
msgid "Help balloons\\Explain the function of the buttons"
msgstr "Bulles d'aide\\Bulles explicatives"
msgid "Hex value out of range"
msgstr ""
#, fuzzy
msgid "Higher speed\\Doubles speed"
msgstr "Vitesse 2.0x\\Deux fois plus rapide"
msgid "Highest\\Highest graphic quality (lowest frame rate)"
msgstr "Maxi\\Haute qualité (+ lent)"
@ -752,6 +759,9 @@ msgstr "Instructions mission\\Marche à suivre"
msgid "Internal error - tell the developers"
msgstr "Erreur interne - contacter les développeurs"
msgid "Invalid universal character name"
msgstr ""
msgid "Invert\\Invert values on this axis"
msgstr "Inversion\\Inverse les valeurs sur cet axe"
@ -827,6 +837,23 @@ msgstr "Chargement des objets"
msgid "Loading terrain"
msgstr "Chargement du terrain"
# msgid "Speed 0.5x\\Half speed"
# msgstr ""
# msgid "Speed 1.0x\\Normal speed"
# msgstr ""
# msgid "Speed 1.5x\\1.5 times faster"
# msgstr ""
# msgid "Speed 2.0x\\Double speed"
# msgstr ""
# msgid "Speed 3.0x\\Triple speed"
# msgstr ""
# msgid "Speed 4.0x\\Quadruple speed"
# msgstr ""
# msgid "Speed 6.0x\\Sextuple speed"
# msgstr ""
msgid "Lower speed\\Decrease speed by half"
msgstr ""
msgid "Lowest\\Minimum graphic quality (highest frame rate)"
msgstr "Mini\\Qualité minimale (+ rapide)"
@ -845,6 +872,12 @@ msgstr "Taille réduite"
msgid "Mipmap level\\Mipmap level"
msgstr "Niveau de MIP mapping\\Niveau de MIP mapping"
msgid "Missing end quote"
msgstr ""
msgid "Missing hex digits after escape sequence"
msgstr ""
msgid "Mission name"
msgstr "Nom de la mission"
@ -1007,6 +1040,9 @@ msgstr "D'accord\\Compiler le programme"
msgid "Object too close"
msgstr "Objet trop proche"
msgid "Octal value out of range"
msgstr ""
msgid "One step"
msgstr "Un pas"
@ -1181,6 +1217,16 @@ msgstr "Public\\Dossier commun à tous les joueurs"
msgid "Quake at explosions\\The screen shakes at explosions"
msgstr "Secousses lors d'explosions\\L'écran vibre lors d'une explosion"
msgid "Quick load\\Immediately load game"
msgstr ""
msgid "Quick save\\Immediately save game"
msgstr ""
#, fuzzy
msgid "Quicksave slot not found"
msgstr "Objet n'existe pas"
msgid "Quit\\Quit Colobot: Gold Edition"
msgstr "Quitter\\Quitter Colobot : Édition Gold"
@ -1391,27 +1437,6 @@ msgstr "Vaisseau spatial"
msgid "Spaceship ruin"
msgstr "Epave de vaisseau spatial"
msgid "Speed 0.5x\\Half speed"
msgstr "Vitesse 0.5x\\Demi-vitesse"
msgid "Speed 1.0x\\Normal speed"
msgstr "Vitesse 1.0x\\Vitesse normale"
msgid "Speed 1.5x\\1.5 times faster"
msgstr "Vitesse 1.5x\\Une fois et demi plus rapide"
msgid "Speed 2.0x\\Double speed"
msgstr "Vitesse 2.0x\\Deux fois plus rapide"
msgid "Speed 3.0x\\Triple speed"
msgstr "Vitesse 3.0x\\Trois fois plus rapide "
msgid "Speed 4.0x\\Quadruple speed"
msgstr "Vitesse 4.0x\\Quatre fois plus rapide"
msgid "Speed 6.0x\\Sextuple speed"
msgstr "Vitesse 6.0x\\Six fois plus rapide"
msgid "Spider"
msgstr "Araignée"
@ -1427,6 +1452,9 @@ msgstr "Action standard\\Action du bouton avec le cadre rouge"
msgid "Standard controls\\Standard key functions"
msgstr "Tout réinitialiser\\Remet toutes les touches standards"
msgid "Standard speed\\Reset speed to normal"
msgstr ""
msgid "Standard\\Standard appearance settings"
msgstr "Standard\\Remet les couleurs standards"
@ -1616,6 +1644,9 @@ msgstr "Objet n'existe pas"
msgid "Unknown command"
msgstr "Commande inconnue"
msgid "Unknown escape sequence"
msgstr ""
msgid "Unknown function"
msgstr "Routine inconnue"
@ -1932,9 +1963,6 @@ msgstr "epsitec.com"
#~ msgid "Num of decorative objects\\Number of purely ornamental objects"
#~ msgstr "Nb d'objets décoratifs\\Qualité d'objets non indispensables"
#~ msgid "Object not found"
#~ msgstr "Objet n'existe pas"
#~ msgid "Planets and stars\\Astronomical objects in the sky"
#~ msgstr "Planètes et étoiles\\Motifs mobiles dans le ciel"
@ -1950,9 +1978,27 @@ msgstr "epsitec.com"
#~ msgid "Sky\\Clouds and nebulae"
#~ msgstr "Ciel\\Ciel et nuages"
#~ msgid "Speed 0.5x\\Half speed"
#~ msgstr "Vitesse 0.5x\\Demi-vitesse"
#~ msgid "Speed 1.0x\\Normal speed"
#~ msgstr "Vitesse 1.0x\\Vitesse normale"
#~ msgid "Speed 1.5x\\1.5 times faster"
#~ msgstr "Vitesse 1.5x\\Une fois et demi plus rapide"
#~ msgid "Speed 3.0x\\Three times faster"
#~ msgstr "Vitesse 3.0x\\Trois fois plus rapide"
#~ msgid "Speed 3.0x\\Triple speed"
#~ msgstr "Vitesse 3.0x\\Trois fois plus rapide "
#~ msgid "Speed 4.0x\\Quadruple speed"
#~ msgstr "Vitesse 4.0x\\Quatre fois plus rapide"
#~ msgid "Speed 6.0x\\Sextuple speed"
#~ msgstr "Vitesse 6.0x\\Six fois plus rapide"
#~ msgid "Sunbeams\\Sunbeams in the sky"
#~ msgstr "Rayons du soleil\\Rayons selon l'orientation"

View File

@ -678,6 +678,12 @@ msgstr "Pomoc na temat zaznaczonego obiektu"
msgid "Help balloons\\Explain the function of the buttons"
msgstr "Dymki pomocy\\Wyjaśnia funkcje przycisków"
msgid "Hex value out of range"
msgstr ""
msgid "Higher speed\\Doubles speed"
msgstr "Zwiększ prędkość\\Podwaja prędkość"
msgid "Highest\\Highest graphic quality (lowest frame rate)"
msgstr "Najwyższa\\Maksymalna jakość grafiki (najniższa częstotliwość odświeżania)"
@ -753,6 +759,9 @@ msgstr "Rozkazy\\Pokazuje rozkazy dotyczące bieżącej misji"
msgid "Internal error - tell the developers"
msgstr "Błąd wewnętrzny - powiadom twórców gry"
msgid "Invalid universal character name"
msgstr ""
msgid "Invert\\Invert values on this axis"
msgstr "Odwróć\\Odwróć wartości na tej osi"
@ -828,6 +837,9 @@ msgstr "Wczytywanie obiektów"
msgid "Loading terrain"
msgstr "Wczytywanie terenu"
msgid "Lower speed\\Decrease speed by half"
msgstr "Zmniejsz prędkość\\Zmniejsza prędkość o połowę"
msgid "Lowest\\Minimum graphic quality (highest frame rate)"
msgstr "Najniższa\\Minimalna jakość grafiki (najwyższa częstotliwość odświeżania)"
@ -846,6 +858,12 @@ msgstr "Pomniejsz"
msgid "Mipmap level\\Mipmap level"
msgstr "Poziom mipmap\\Poziom mipmap"
msgid "Missing end quote"
msgstr ""
msgid "Missing hex digits after escape sequence"
msgstr ""
msgid "Mission name"
msgstr "Nazwa misji"
@ -1008,6 +1026,9 @@ msgstr "OK\\Zamyka edytor programu i powraca do gry"
msgid "Object too close"
msgstr "Obiekt za blisko"
msgid "Octal value out of range"
msgstr ""
msgid "One step"
msgstr "Jeden krok"
@ -1182,6 +1203,15 @@ msgstr "Publiczny\\Folder ogólnodostępny"
msgid "Quake at explosions\\The screen shakes at explosions"
msgstr "Wstrząsy przy wybuchach\\Ekran trzęsie się podczas wybuchów"
msgid "Quick load\\Immediately load game"
msgstr "Szybkie wczytywanie\\Natychmiastowo wczytuje zapisaną grę"
msgid "Quick save\\Immediately save game"
msgstr "Szybki zapis\\Natychmiastowo zapisuje grę"
msgid "Quicksave slot not found"
msgstr "Nie odnaleziono slotu szybkiego zapisu"
msgid "Quit\\Quit Colobot: Gold Edition"
msgstr "Wyjdź\\Kończy grę Colobot: Gold Edition"
@ -1392,27 +1422,6 @@ msgstr "Statek kosmiczny"
msgid "Spaceship ruin"
msgstr "Ruiny statku kosmicznego"
msgid "Speed 0.5x\\Half speed"
msgstr "Prędkość 0,5x\\Połowa prękości"
msgid "Speed 1.0x\\Normal speed"
msgstr "Prędkość 1,0x\\Prędkość normalna"
msgid "Speed 1.5x\\1.5 times faster"
msgstr "Prędkość 1,5x\\1,5 raza szybciej"
msgid "Speed 2.0x\\Double speed"
msgstr "Prędkość 2,0x\\Dwa razy szybciej"
msgid "Speed 3.0x\\Triple speed"
msgstr "Prędkość 3,0x\\Trzy razy szybciej"
msgid "Speed 4.0x\\Quadruple speed"
msgstr "Prędkość 4,0x\\Cztery razy szybciej"
msgid "Speed 6.0x\\Sextuple speed"
msgstr "Prędkość 6,0x\\Sześć razy szybciej"
msgid "Spider"
msgstr "Pająk"
@ -1428,6 +1437,9 @@ msgstr "Standardowa akcja\\Standardowa akcja robota (podnieś/upuść, strzelaj,
msgid "Standard controls\\Standard key functions"
msgstr "Standardowa kontrola\\Standardowe klawisze funkcyjne"
msgid "Standard speed\\Reset speed to normal"
msgstr "Standardowa prędkość\\Resetuje prędkość do wartości domyślnej"
msgid "Standard\\Standard appearance settings"
msgstr "Standardowe\\Standardowe ustawienia wyglądu"
@ -1617,6 +1629,9 @@ msgstr "Obiekt nieznany"
msgid "Unknown command"
msgstr "Nieznane polecenie"
msgid "Unknown escape sequence"
msgstr ""
msgid "Unknown function"
msgstr "Funkcja nieznana"

View File

@ -686,6 +686,13 @@ msgstr "Справка о выбранном объекте"
msgid "Help balloons\\Explain the function of the buttons"
msgstr "Подсказки\\Объяснение функций кнопок"
msgid "Hex value out of range"
msgstr ""
#, fuzzy
msgid "Higher speed\\Doubles speed"
msgstr "Скорость 2.0х\\В два раза быстрее"
msgid "Highest\\Highest graphic quality (lowest frame rate)"
msgstr "Высок.\\Самые высокие настройки графики (лучшее качество)"
@ -761,6 +768,9 @@ msgstr "Инструкции\\Показывает инструкции по т
msgid "Internal error - tell the developers"
msgstr "Внутренняя ошибка - сообщите разработчикам"
msgid "Invalid universal character name"
msgstr ""
msgid "Invert\\Invert values on this axis"
msgstr "Инвертир.\\Инвертировать значения по этой оси"
@ -836,6 +846,23 @@ msgstr "Загрузка объектов"
msgid "Loading terrain"
msgstr "Загрузка местности"
# msgid "Speed 0.5x\\Half speed"
# msgstr ""
# msgid "Speed 1.0x\\Normal speed"
# msgstr ""
# msgid "Speed 1.5x\\1.5 times faster"
# msgstr ""
# msgid "Speed 2.0x\\Double speed"
# msgstr ""
# msgid "Speed 3.0x\\Triple speed"
# msgstr ""
# msgid "Speed 4.0x\\Quadruple speed"
# msgstr ""
# msgid "Speed 6.0x\\Sextuple speed"
# msgstr ""
msgid "Lower speed\\Decrease speed by half"
msgstr ""
msgid "Lowest\\Minimum graphic quality (highest frame rate)"
msgstr "Низкое\\Минимальное качество графики (быстро)"
@ -854,6 +881,12 @@ msgstr "Свернуть"
msgid "Mipmap level\\Mipmap level"
msgstr "Уровень уменьшающей фильтрации\\Уровень уменьшающей фильтрации"
msgid "Missing end quote"
msgstr ""
msgid "Missing hex digits after escape sequence"
msgstr ""
msgid "Mission name"
msgstr "Название миссии"
@ -1018,6 +1051,9 @@ msgstr "ОК\\Закрыть редактор программ и вернуть
msgid "Object too close"
msgstr "Объект слишком близок"
msgid "Octal value out of range"
msgstr ""
msgid "One step"
msgstr "Один шаг"
@ -1193,6 +1229,16 @@ msgstr "Общее\\Общая папка"
msgid "Quake at explosions\\The screen shakes at explosions"
msgstr "Землетряс. при взрывах\\Тряска экрана при взрывах"
msgid "Quick load\\Immediately load game"
msgstr ""
msgid "Quick save\\Immediately save game"
msgstr ""
#, fuzzy
msgid "Quicksave slot not found"
msgstr "Объект не найден"
msgid "Quit\\Quit Colobot: Gold Edition"
msgstr "Выход\\Выйти из Colobot: Gold Edition"
@ -1406,27 +1452,6 @@ msgstr "Космический корабль"
msgid "Spaceship ruin"
msgstr "Обломки корабля"
msgid "Speed 0.5x\\Half speed"
msgstr "Скорость 0.5х\\В два раза медленнее"
msgid "Speed 1.0x\\Normal speed"
msgstr "Скорость 1.0х\\Нормальная скорость"
msgid "Speed 1.5x\\1.5 times faster"
msgstr "Скорость 1.5х\\В полтора раза быстрее"
msgid "Speed 2.0x\\Double speed"
msgstr "Скорость 2.0х\\В два раза быстрее"
msgid "Speed 3.0x\\Triple speed"
msgstr "Скорость 3.0х\\В три раза быстрее"
msgid "Speed 4.0x\\Quadruple speed"
msgstr "Скорость 4.0х\\В четыре раза быстрее"
msgid "Speed 6.0x\\Sextuple speed"
msgstr "Скорость 6.0х\\В шесть раз быстрее"
msgid "Spider"
msgstr "Паук"
@ -1442,6 +1467,9 @@ msgstr "Стандартное действие\\Стандартное дейс
msgid "Standard controls\\Standard key functions"
msgstr "Стандартное управление\\Сделать управление по умолчанию"
msgid "Standard speed\\Reset speed to normal"
msgstr ""
msgid "Standard\\Standard appearance settings"
msgstr "По умолчанию\\Настройки внешнего вида по умолчанию"
@ -1632,6 +1660,9 @@ msgstr "Неизвестный объект"
msgid "Unknown command"
msgstr "Неизвестная команда"
msgid "Unknown escape sequence"
msgstr ""
msgid "Unknown function"
msgstr "Неизвестная функция"
@ -1942,9 +1973,6 @@ msgstr "epsitec.com"
#~ msgid "Num of decorative objects\\Number of purely ornamental objects"
#~ msgstr "Количество декораций\\Количество декоративных объектов"
#~ msgid "Object not found"
#~ msgstr "Объект не найден"
#~ msgid "Planets and stars\\Astronomical objects in the sky"
#~ msgstr "Планеты и звезды\\Астрономические объекты в небе"
@ -1960,9 +1988,27 @@ msgstr "epsitec.com"
#~ msgid "Sky\\Clouds and nebulae"
#~ msgstr "Небо\\Облака и туманности"
#~ msgid "Speed 0.5x\\Half speed"
#~ msgstr "Скорость 0.5х\\В два раза медленнее"
#~ msgid "Speed 1.0x\\Normal speed"
#~ msgstr "Скорость 1.0х\\Нормальная скорость"
#~ msgid "Speed 1.5x\\1.5 times faster"
#~ msgstr "Скорость 1.5х\\В полтора раза быстрее"
#~ msgid "Speed 3.0x\\Three times faster"
#~ msgstr "Скорость 3.0х\\В три раза быстрее"
#~ msgid "Speed 3.0x\\Triple speed"
#~ msgstr "Скорость 3.0х\\В три раза быстрее"
#~ msgid "Speed 4.0x\\Quadruple speed"
#~ msgstr "Скорость 4.0х\\В четыре раза быстрее"
#~ msgid "Speed 6.0x\\Sextuple speed"
#~ msgstr "Скорость 6.0х\\В шесть раз быстрее"
#~ msgid "Sunbeams\\Sunbeams in the sky"
#~ msgstr "Солнечные лучи\\Солнечные лучи в небе"

View File

@ -241,6 +241,12 @@ enum CBotError : int
CBotErrNoClassName = 5046, //!< class name expected
CBotErrNoReturn = 5047, //!< non-void function needs "return;"
CBotErrDefaultValue = 5048, //!< this parameter needs a default value
CBotErrEndQuote = 5049, //!< missing end quote
CBotErrBadEscape = 5050, //!< unknown escape sequence
CBotErrOctalRange = 5051, //!< octal value out of range
CBotErrHexDigits = 5052, //!< missing hex digits after escape sequence
CBotErrHexRange = 5053, //!< hex value out of range
CBotErrUnicodeName = 5054, //!< invalid universal character name
// Runtime errors
CBotErrZeroDiv = 6000, //!< division by zero

View File

@ -42,8 +42,124 @@ CBotInstr* CBotExprLitString::Compile(CBotToken* &p, CBotCStack* pStack)
{
CBotCStack* pStk = pStack->TokenStack();
CBotExprLitString* inst = new CBotExprLitString();
std::string s = p->GetString();
auto it = s.cbegin();
if (++it != s.cend())
{
int pos = p->GetStart();
std::string valstring = "";
while (it != s.cend() && *it != '\"')
{
pStk->SetStartError(++pos);
if (*it != '\\') // not escape sequence ?
{
valstring += *(it++);
continue;
}
if (++it == s.cend()) break;
if (CharInList(*it, "01234567")) // octal
{
std::string octal = "";
for (int i = 0; i < 3; i++)
{
if (!CharInList(*it, "01234567")) break;
++pos;
octal += *it;
if (++it == s.cend()) break;
}
unsigned int val = std::stoi(octal, nullptr, 8);
if (val <= 255)
{
valstring.push_back(val);
continue;
}
pStk->SetError(CBotErrOctalRange, pos + 1);
}
else
{
++pos;
unsigned char c = *(it++);
if (c == '\"' || c == '\'' || c == '\\') valstring += c;
else if (c == 'a') valstring += '\a'; // alert bell
else if (c == 'b') valstring += '\b'; // backspace
else if (c == 'f') valstring += '\f'; // form feed
else if (c == 'n') valstring += '\n'; // new line
else if (c == 'r') valstring += '\r'; // carriage return
else if (c == 't') valstring += '\t'; // horizontal tab
else if (c == 'v') valstring += '\v'; // vertical tab
else if (c == 'x' || c == 'u' || c == 'U') // hex or unicode
{
if (it != s.cend())
{
std::string hex = "";
bool isHexCode = (c == 'x');
size_t maxlen = (c == 'u') ? 4 : 8;
for (size_t i = 0; isHexCode || i < maxlen; i++)
{
if (!CharInList(*it, "0123456789ABCDEFabcdef")) break;
++pos;
hex += *it;
if (++it == s.cend()) break;
}
if (!hex.empty())
{
unsigned int val = 0;
try
{
val = std::stoi(hex, nullptr, 16);
}
catch (const std::out_of_range& e)
{
pStk->SetError(CBotErrHexRange, pos + 1);
}
if (pStk->IsOk())
{
if (isHexCode) // hexadecimal
{
if (val <= 255)
{
valstring.push_back(val);
continue;
}
pStk->SetError(CBotErrHexRange, pos + 1);
}
else if (maxlen == hex.length()) // unicode character
{
if (val < 0xD800 || (0xDFFF < val && val < 0x110000))
{
valstring += CodePointToUTF8(val);
continue;
}
pStk->SetError(CBotErrUnicodeName, pos + 1);
}
}
}
}
pStk->SetError(CBotErrHexDigits, pos + 1);
}
else
pStk->SetError(CBotErrBadEscape, pos + 1); // unknown escape code
}
if (!pStk->IsOk()) break;
}
if (it == s.cend() || *it != '\"')
pStk->SetError(CBotErrEndQuote, p);
if (pStk->IsOk())
{
CBotExprLitString* inst = new CBotExprLitString();
inst->m_valstring.swap(valstring);
inst->SetToken(p);
p = p->GetNext();
@ -51,6 +167,11 @@ CBotInstr* CBotExprLitString::Compile(CBotToken* &p, CBotCStack* pStack)
pStk->SetVar(var);
return pStack->Return(inst, pStk);
}
}
pStk->SetError(CBotErrEndQuote, p);
return pStack->Return(nullptr, pStk);
}
////////////////////////////////////////////////////////////////////////////////
@ -62,10 +183,7 @@ bool CBotExprLitString::Execute(CBotStack* &pj)
CBotVar* var = CBotVar::Create("", CBotTypString);
std::string chaine = m_token.GetString();
chaine = chaine.substr(1, chaine.length()-2); // removes the quotes
var->SetValString(chaine); // value of the number
var->SetValString(m_valstring);
pile->SetVar(var); // put on the stack

View File

@ -58,6 +58,9 @@ public:
protected:
virtual const std::string GetDebugName() override { return "CBotExprLitString"; }
virtual std::string GetDebugData() override;
private:
std::string m_valstring = "";
};
} // namespace CBot

View File

@ -76,6 +76,8 @@ CBotInstr* CBotExprVar::Compile(CBotToken*& p, CBotCStack* pStack, bool bCheckRe
// This is an element of the current class
// ads the equivalent of this. before
CBotToken token("this");
// invisible 'this.' highlights member token on error
token.SetPos(p->GetStart(), p->GetEnd());
inst->SetToken(&token);
(static_cast<CBotExprVar*>(inst))->m_nIdent = -2; // identificator for this
@ -196,6 +198,8 @@ CBotInstr* CBotExprVar::CompileMethode(CBotToken* &p, CBotCStack* pStack)
// this is an element of the current class
// adds the equivalent of this. before
// invisible 'this.' highlights member token on error
pthis.SetPos(pp->GetStart(), pp->GetEnd());
inst->SetToken(&pthis);
(static_cast<CBotExprVar*>(inst))->m_nIdent = -2; // ident for this

View File

@ -464,6 +464,7 @@ void CBotFunction::RestoreState(CBotVar** ppVars, CBotStack* &pj, CBotVar* pInst
{
CBotVar* pThis = pile->FindVar("this");
pThis->SetInit(CBotVar::InitType::IS_POINTER);
pThis->SetPointer(pInstance);
pThis->SetUniqNum(-2);
}
@ -672,6 +673,7 @@ int CBotFunction::DoCall(CBotProgram* program, const std::list<CBotFunction*>& l
{
CBotTypResult type;
CBotFunction* pt = nullptr;
CBotProgram* baseProg = pStack->GetProgram(true);
pt = FindLocalOrPublic(localFunctionList, nIdent, name, ppVars, type);
@ -695,7 +697,7 @@ int CBotFunction::DoCall(CBotProgram* program, const std::list<CBotFunction*>& l
if (pStk3b->GetState() == 0 && !pt->m_MasterClass.empty())
{
CBotVar* pInstance = program->m_thisVar;
CBotVar* pInstance = (baseProg != nullptr) ? baseProg->m_thisVar : nullptr;
// make "this" known
CBotVar* pThis ;
if ( pInstance == nullptr )
@ -762,8 +764,7 @@ void CBotFunction::RestoreCall(const std::list<CBotFunction*>& localFunctionList
CBotFunction* pt = nullptr;
CBotStack* pStk1;
CBotStack* pStk3;
// search function to return the ok identifier
CBotProgram* baseProg = pStack->GetProgram(true);
pt = FindLocalOrPublic(localFunctionList, nIdent, name, ppVars, type);
@ -792,10 +793,11 @@ void CBotFunction::RestoreCall(const std::list<CBotFunction*>& localFunctionList
{
if ( !pt->m_MasterClass.empty() )
{
// CBotVar* pInstance = m_pProg->m_thisVar;
CBotVar* pInstance = (baseProg != nullptr) ? baseProg->m_thisVar : nullptr;
// make "this" known
CBotVar* pThis = pStk1->FindVar("this");
pThis->SetInit(CBotVar::InitType::IS_POINTER);
pThis->SetPointer(pInstance);
pThis->SetUniqNum(-2);
}
}

View File

@ -72,6 +72,8 @@ CBotLeftExpr* CBotLeftExpr::Compile(CBotToken* &p, CBotCStack* pStack)
// this is an element of the current class
// adds the equivalent of this. before
CBotToken pthis("this");
// invisible 'this.' highlights member token on error
pthis.SetPos(p->GetStart(), p->GetEnd());
inst->SetToken(&pthis);
inst->m_nIdent = -2; // indent for this

View File

@ -405,9 +405,20 @@ bool CBotTwoOpExpr::Execute(CBotStack* &pStack)
// creates a variable for the result
CBotVar* result = CBotVar::Create("", TypeRes);
// get left and right operands
CBotVar* left = pStk1->GetVar();
CBotVar* right = pStk2->GetVar();
// creates a variable to perform the calculation in the appropriate type
if ( TypeRes != CBotTypString ) // keep string conversion
{
TypeRes = std::max(type1.GetType(), type2.GetType());
}
else
{
left->Update(nullptr);
right->Update(nullptr);
}
if ( GetTokenType() == ID_ADD && type1.Eq(CBotTypString) )
{
@ -422,8 +433,6 @@ bool CBotTwoOpExpr::Execute(CBotStack* &pStack)
CBotError err = CBotNoErr;
// is a operation according to request
CBotVar* left = pStk1->GetVar();
CBotVar* right = pStk2->GetVar();
switch (GetTokenType())
{

View File

@ -241,23 +241,13 @@ void CBotToken::SetPos(int start, int end)
}
////////////////////////////////////////////////////////////////////////////////
bool CharInList(const char c, const char* list)
{
int i = 0;
while (true)
{
if (c == list[i++]) return true;
if (list[i] == 0) return false;
}
}
static char sep1[] = " \r\n\t,:()[]{}-+*/=;><!~^|&%.";
static char sep1[] = " \r\n\t,:()[]{}-+*/=;><!~^|&%.\"\'?";
static char sep2[] = " \r\n\t"; // only separators
static char sep3[] = ",:()[]{}-+*/=;<>!~^|&%."; // operational separators
static char sep3[] = ",:()[]{}-+*/=;<>!~^|&%.?"; // operational separators
static char num[] = "0123456789"; // point (single) is tested separately
static char hexnum[] = "0123456789ABCDEFabcdef";
static char nch[] = "\"\r\n\t"; // forbidden in chains
static char nch[] = "\r\n\t"; // forbidden in chains
////////////////////////////////////////////////////////////////////////////////
CBotToken* CBotToken::NextToken(const char*& program, bool first)
@ -278,14 +268,13 @@ CBotToken* CBotToken::NextToken(const char*& program, bool first)
// special case for strings
if (token[0] == '\"' )
{
while (c != 0 && !CharInList(c, nch))
while (c != 0 && c != '\"' && !CharInList(c, nch))
{
if ( c == '\\' )
{
c = *(program++); // next character
if ( c == 'n' ) c = '\n';
if ( c == 'r' ) c = '\r';
if ( c == 't' ) c = '\t';
token += c;
c = *(program++);
if (c == 0 || CharInList(c, nch)) break;
}
token += c;
c = *(program++);

View File

@ -236,4 +236,49 @@ float GetNumFloat(const std::string& str)
return static_cast<float>(num);
}
bool CharInList(const char c, const char* list)
{
int i = 0;
while (list[i] != 0)
{
if (c == list[i++]) return true;
}
return false;
}
std::string CodePointToUTF8(unsigned int val)
{
std::string s = "";
if (val < 0xD800 || (0xDFFF < val && val < 0x110000))
{
if (val < 0x80)
{
s.push_back(val);
}
else if (val < 0x800)
{
s.push_back(0xC0 + (val >> 6));
s.push_back(0x80 + (val & 0x3F));
}
else if (val < 0x10000)
{
s.push_back(0xE0 + (val >> 12));
s.push_back(0x80 + ((val >> 6) & 0x3F));
s.push_back(0x80 + (val & 0x3F));
}
else
{
s.push_back(0xF0 + (val >> 18));
s.push_back(0x80 + ((val >> 12) & 0x3F));
s.push_back(0x80 + ((val >> 6) & 0x3F));
s.push_back(0x80 + (val & 0x3F));
}
}
return s;
}
} // namespace CBot

View File

@ -96,6 +96,21 @@ long GetNumInt(const std::string& str);
*/
float GetNumFloat(const std::string& str);
/*!
* \brief Search a null-terminated string for a char value.
* \param c The char to find.
* \param list The string to search.
* \return true if the char is found.
*/
bool CharInList(const char c, const char* list);
/*!
* \brief Converts a Unicode code point to UTF-8 encoded character.
* \param val Code point value.
* \return UTF-8 encoded string or empty string.
*/
std::string CodePointToUTF8(unsigned int val);
template<typename T> class CBotLinkedList
{
public:

View File

@ -61,9 +61,6 @@
#include <getopt.h>
#include <localename.h>
template<> CApplication* CSingleton<CApplication>::m_instance = nullptr;
char CApplication::m_languageLocale[] = { 0 };

View File

@ -32,9 +32,6 @@
#include <boost/lexical_cast.hpp>
#include <SDL_system.h>
template<> CInput* CSingleton<CInput>::m_instance = nullptr;
CInput::CInput()
: m_keyPresses()
{
@ -62,13 +59,11 @@ CInput::CInput()
{ INPUT_SLOT_HELP, "help" },
{ INPUT_SLOT_PROG, "prog" },
{ INPUT_SLOT_VISIT, "visit" },
{ INPUT_SLOT_SPEED05, "speed05" },
{ INPUT_SLOT_SPEED10, "speed10" },
{ INPUT_SLOT_SPEED15, "speed15" },
{ INPUT_SLOT_SPEED20, "speed20" },
{ INPUT_SLOT_SPEED30, "speed30" },
{ INPUT_SLOT_SPEED40, "speed40" },
{ INPUT_SLOT_SPEED60, "speed60" },
{ INPUT_SLOT_SPEED_DEC, "speed_dec" },
{ INPUT_SLOT_SPEED_RESET,"speed_reset" },
{ INPUT_SLOT_SPEED_INC, "speed_inc" },
{ INPUT_SLOT_QUICKSAVE, "quicksave" },
{ INPUT_SLOT_QUICKLOAD, "quickload" },
{ INPUT_SLOT_PAUSE, "pause" },
{ INPUT_SLOT_CMDLINE, "cmdline" },
};
@ -277,13 +272,11 @@ void CInput::SetDefaultInputBindings()
m_inputBindings[INPUT_SLOT_HELP ].primary = KEY(F1);
m_inputBindings[INPUT_SLOT_PROG ].primary = KEY(F2);
m_inputBindings[INPUT_SLOT_VISIT ].primary = KEY(KP_PERIOD);
m_inputBindings[INPUT_SLOT_SPEED05].primary = KEY(F3);
m_inputBindings[INPUT_SLOT_SPEED10].primary = KEY(F4);
m_inputBindings[INPUT_SLOT_SPEED15].primary = KEY(F5);
m_inputBindings[INPUT_SLOT_SPEED20].primary = KEY(F6);
m_inputBindings[INPUT_SLOT_SPEED30].primary = KEY(F7);
m_inputBindings[INPUT_SLOT_SPEED40].primary = KEY(F8);
m_inputBindings[INPUT_SLOT_SPEED60].primary = KEY(F9);
m_inputBindings[INPUT_SLOT_QUICKSAVE].primary = KEY(F5);
m_inputBindings[INPUT_SLOT_SPEED_DEC].primary = KEY(F6);
m_inputBindings[INPUT_SLOT_SPEED_RESET].primary = KEY(F7);
m_inputBindings[INPUT_SLOT_SPEED_INC].primary = KEY(F8);
m_inputBindings[INPUT_SLOT_QUICKLOAD].primary = KEY(F9);
m_inputBindings[INPUT_SLOT_PAUSE].primary = KEY(PAUSE);
m_inputBindings[INPUT_SLOT_PAUSE].secondary = KEY(p);
m_inputBindings[INPUT_SLOT_CMDLINE].primary = KEY(BACKQUOTE);

View File

@ -37,8 +37,6 @@
#include <boost/algorithm/string.hpp>
#include <boost/filesystem.hpp>
template<> CPathManager* CSingleton<CPathManager>::m_instance = nullptr;
CPathManager::CPathManager(CSystemUtils* systemUtils)
: m_systemUtils(systemUtils)
{

View File

@ -34,9 +34,6 @@
#include <boost/property_tree/ini_parser.hpp>
#include <boost/regex.hpp>
template<> CConfigFile* CSingleton<CConfigFile>::m_instance = nullptr;
namespace bp = boost::property_tree;
CConfigFile::CConfigFile()

View File

@ -112,6 +112,7 @@ enum Error
ERR_PROHIBITEDTOKEN = 801, //!< instruction prohibited
ERR_AIM_IMPOSSIBLE = 900, //!< cannot aim at specified angle(s)
ERR_WRONG_BOT = 910, //!< inappropriate bot
ERR_NO_QUICK_SLOT = 920, //!< quicksave slot not found
INFO_FIRST = 10000, //! < first information
INFO_BUILD = 10001, //! < construction builded

View File

@ -100,13 +100,11 @@ enum InputSlot
INPUT_SLOT_HELP,
INPUT_SLOT_PROG,
INPUT_SLOT_VISIT,
INPUT_SLOT_SPEED05,
INPUT_SLOT_SPEED10,
INPUT_SLOT_SPEED15,
INPUT_SLOT_SPEED20,
INPUT_SLOT_SPEED30,
INPUT_SLOT_SPEED40,
INPUT_SLOT_SPEED60,
INPUT_SLOT_SPEED_DEC,
INPUT_SLOT_SPEED_RESET,
INPUT_SLOT_SPEED_INC,
INPUT_SLOT_QUICKSAVE,
INPUT_SLOT_QUICKLOAD,
INPUT_SLOT_PAUSE,
INPUT_SLOT_CMDLINE,

View File

@ -22,10 +22,6 @@
#include <stdio.h>
template<> CLogger* CSingleton<CLogger>::m_instance = nullptr;
CLogger::CLogger()
{
#if DEV_BUILD

View File

@ -240,13 +240,11 @@ void InitializeRestext()
stringsEvent[EVENT_INTERFACE_KEY+INPUT_SLOT_HELP] = TR("Instructions\\Shows the instructions for the current mission");
stringsEvent[EVENT_INTERFACE_KEY+INPUT_SLOT_PROG] = TR("Programming help\\Gives more detailed help with programming");
stringsEvent[EVENT_INTERFACE_KEY+INPUT_SLOT_VISIT] = TR("Origin of last message\\Shows where the last message was sent from");
stringsEvent[EVENT_INTERFACE_KEY+INPUT_SLOT_SPEED05] = TR("Speed 0.5x\\Half speed");
stringsEvent[EVENT_INTERFACE_KEY+INPUT_SLOT_SPEED10] = TR("Speed 1.0x\\Normal speed");
stringsEvent[EVENT_INTERFACE_KEY+INPUT_SLOT_SPEED15] = TR("Speed 1.5x\\1.5 times faster");
stringsEvent[EVENT_INTERFACE_KEY+INPUT_SLOT_SPEED20] = TR("Speed 2.0x\\Double speed");
stringsEvent[EVENT_INTERFACE_KEY+INPUT_SLOT_SPEED30] = TR("Speed 3.0x\\Triple speed");
stringsEvent[EVENT_INTERFACE_KEY+INPUT_SLOT_SPEED40] = TR("Speed 4.0x\\Quadruple speed");
stringsEvent[EVENT_INTERFACE_KEY+INPUT_SLOT_SPEED60] = TR("Speed 6.0x\\Sextuple speed");
stringsEvent[EVENT_INTERFACE_KEY+INPUT_SLOT_SPEED_DEC] = TR("Lower speed\\Decrease speed by half");
stringsEvent[EVENT_INTERFACE_KEY+INPUT_SLOT_SPEED_RESET] = TR("Standard speed\\Reset speed to normal");
stringsEvent[EVENT_INTERFACE_KEY+INPUT_SLOT_SPEED_INC] = TR("Higher speed\\Doubles speed");
stringsEvent[EVENT_INTERFACE_KEY+INPUT_SLOT_QUICKSAVE] = TR("Quick save\\Immediately save game");
stringsEvent[EVENT_INTERFACE_KEY+INPUT_SLOT_QUICKLOAD] = TR("Quick load\\Immediately load game");
stringsEvent[EVENT_INTERFACE_KEY+INPUT_SLOT_PAUSE] = TR("Pause\\Pause the game without opening menu");
stringsEvent[EVENT_INTERFACE_KEY+INPUT_SLOT_CMDLINE] = TR("Cheat console\\Show cheat console");
@ -643,6 +641,7 @@ void InitializeRestext()
stringsErr[ERR_DELETEBUILDING] = TR("Building destroyed");
stringsErr[ERR_ENEMY_OBJECT] = TR("Unable to control enemy objects");
stringsErr[ERR_WRONG_BOT] = TR("Inappropriate bot");
stringsErr[ERR_NO_QUICK_SLOT] = TR("Quicksave slot not found");
stringsErr[INFO_BUILD] = TR("Building completed");
stringsErr[INFO_CONVERT] = TR("Titanium available");
@ -732,6 +731,12 @@ void InitializeRestext()
stringsCbot[CBot::CBotErrNoClassName] = TR("Class name expected");
stringsCbot[CBot::CBotErrNoReturn] = TR("Non-void function needs \"return;\"");
stringsCbot[CBot::CBotErrDefaultValue] = TR("This parameter needs a default value");
stringsCbot[CBot::CBotErrEndQuote] = TR("Missing end quote");
stringsCbot[CBot::CBotErrBadEscape] = TR("Unknown escape sequence");
stringsCbot[CBot::CBotErrOctalRange] = TR("Octal value out of range");
stringsCbot[CBot::CBotErrHexDigits] = TR("Missing hex digits after escape sequence");
stringsCbot[CBot::CBotErrHexRange] = TR("Hex value out of range");
stringsCbot[CBot::CBotErrUnicodeName] = TR("Invalid universal character name");
stringsCbot[CBot::CBotErrZeroDiv] = TR("Dividing by zero");
stringsCbot[CBot::CBotErrNotInit] = TR("Variable not initialized");

View File

@ -32,8 +32,6 @@
#include "sound/sound.h"
template<> CSettings* CSingleton<CSettings>::m_instance = nullptr;
CSettings::CSettings()
{
m_tooltips = true;
@ -123,6 +121,8 @@ void CSettings::SaveSettings()
GetConfigFile().SetFloatProperty("Edit", "WindowPosY", m_windowPos.y);
GetConfigFile().SetFloatProperty("Edit", "WindowDimX", m_windowDim.x);
GetConfigFile().SetFloatProperty("Edit", "WindowDimY", m_windowDim.y);
GetConfigFile().SetBoolProperty ("Edit", "WindowMaximized", m_windowMax);
GetConfigFile().SetBoolProperty("Edit", "IOPublic", m_IOPublic);
GetConfigFile().SetFloatProperty("Edit", "IOPosX", m_IOPos.x);
GetConfigFile().SetFloatProperty("Edit", "IOPosY", m_IOPos.y);
@ -283,6 +283,7 @@ void CSettings::LoadSettings()
GetConfigFile().GetFloatProperty("Edit", "WindowPosY", m_windowPos.y);
GetConfigFile().GetFloatProperty("Edit", "WindowDimX", m_windowDim.x);
GetConfigFile().GetFloatProperty("Edit", "WindowDimY", m_windowDim.y);
GetConfigFile().GetBoolProperty ("Edit", "WindowMaximized", m_windowMax);
GetConfigFile().GetBoolProperty ("Edit", "IOPublic", m_IOPublic);
GetConfigFile().GetFloatProperty("Edit", "IOPosX", m_IOPos.x);
@ -395,6 +396,18 @@ Math::Point CSettings::GetWindowDim()
return m_windowDim;
}
void CSettings::SetWindowMax(bool max)
{
m_windowMax = max;
GetConfigFile().SetBoolProperty("Edit", "WindowMaximized", m_windowMax);
GetConfigFile().Save();
}
bool CSettings::GetWindowMax()
{
return m_windowMax;
}
void CSettings::SetIOPublic(bool mode)
{
m_IOPublic = mode;

View File

@ -70,6 +70,9 @@ public:
void SetWindowDim(Math::Point dim);
Math::Point GetWindowDim();
void SetWindowMax(bool max);
bool GetWindowMax();
//@}
//! Managing windows open/save
@ -98,6 +101,7 @@ protected:
float m_fontSize;
Math::Point m_windowPos;
Math::Point m_windowDim;
bool m_windowMax;
bool m_IOPublic;
Math::Point m_IOPos;

View File

@ -73,3 +73,4 @@ private:
CSingleton(const CSingleton<T> &) = delete;
};
template <typename T> T* CSingleton<T>::m_instance = nullptr;

View File

@ -64,8 +64,6 @@
#include <SDL_surface.h>
#include <SDL_thread.h>
template<> Gfx::CEngine* CSingleton<Gfx::CEngine>::m_instance = nullptr;
// Graphics module namespace
namespace Gfx
{
@ -2633,6 +2631,10 @@ void CEngine::SetFocus(float focus)
float farPlane = m_deepView[0] * m_clippingDistance;
float aspect = static_cast<float>(m_size.x) / static_cast<float>(m_size.y);
// Compute H-FoV from V-FoV and aspect ratio.
m_hfov = 2.0f * atan(aspect * tan(focus / 2.0f));
Math::LoadProjectionMatrix(m_matProj, m_focus, aspect, 0.5f, farPlane);
}
@ -2641,6 +2643,16 @@ float CEngine::GetFocus()
return m_focus;
}
float CEngine::GetVFovAngle()
{
return m_focus;
}
float CEngine::GetHFovAngle()
{
return m_hfov;
}
void CEngine::SetShadowColor(float value)
{
m_shadowColor = value;
@ -3740,6 +3752,7 @@ void CEngine::RenderShadowMap()
m_shadowMapping = false;
m_offscreenShadowRendering = false;
m_qualityShadows = false;
CProfiler::StopPerformanceCounter(PCNT_RENDER_SHADOW_MAP);
return;
}
@ -4728,8 +4741,9 @@ void CEngine::DrawBackgroundImage()
if (a > Math::PI/4.0f) a = Math::PI/4.0f;
if (a < -Math::PI/4.0f) a = -Math::PI/4.0f;
u1 = -m_eyeDirH/Math::PI;
u2 = u1+1.0f/Math::PI;
// Note the background covers Math::PI radians, i.e. it repeats twice per rotation!
u1 = (-m_eyeDirH - GetHFovAngle()/2.0f) / Math::PI;
u2 = u1 + (GetHFovAngle() / Math::PI);
v1 = (1.0f-h)*(0.5f+a/(2.0f*Math::PI/4.0f))+0.1f;
v2 = v1+h;

View File

@ -869,6 +869,9 @@ public:
//! Specifies the location and direction of view
void SetViewParams(const Math::Vector &eyePt, const Math::Vector &lookatPt, const Math::Vector &upVec);
//! Updates the textures used for drawing ground spot
void UpdateGroundSpotTextures();
//! Loads texture, creating it if not already present
Texture LoadTexture(const std::string& name);
//! Loads texture from existing image
@ -918,12 +921,16 @@ public:
void SetTerrainVision(float vision);
//@{
//! Management of camera angle
/**
//! Management of camera vertical field-of-view angle.
/** This is specified in radians.
Horizontal FoV is calculated based on vertical FoV and aspect ratio.
0.75 = normal
1.50 = wide-angle */
void SetFocus(float focus);
//! Deprecated alias for GetVFovAngle
float GetFocus();
float GetVFovAngle();
float GetHFovAngle();
//@}
//@{
@ -1197,9 +1204,6 @@ protected:
//! Draws the user interface over the scene
void DrawInterface();
//! Updates the textures used for drawing ground spot
void UpdateGroundSpotTextures();
//! Draws old-style shadow spots
void DrawShadowSpots();
//! Draws the gradient background
@ -1318,8 +1322,10 @@ protected:
Math::Matrix m_matProj;
//! View matrix for 3D scene
Math::Matrix m_matView;
//! Camera angle for 3D scene
//! Camera vertical field-of-view angle for 3D scene. A.k.a. m_vfov
float m_focus;
//! Horizontal field-of-view angle, calculated from vertical FOV and aspect ratio
float m_hfov;
//! Projection matrix for rendering shadow maps
Math::Matrix m_shadowProjMat;

View File

@ -115,8 +115,16 @@ void CPlanet::Draw()
Math::Point p1, p2;
float a = eyeDirH + planet.angle.x;
p1.x = Math::Mod(a, Math::PI*2.0f)-0.5f;
// Determine the 2D coordinates of the centre of the planet.
// Not sure why this is + when you'd expect -. Perhaps one of the angles is inverted.
// Compute the camera-relative angles. (0, 0) is straight ahead (the dead centre of the screen).
// Why -1.0f? Simply because the old formula included that, and we need it to
// be consistent for the outer space cutscenes to work.
float a = planet.angle.x + eyeDirH - 1.0f;
a = Math::Mod(a+Math::PI, Math::PI*2.0f)-Math::PI; // normalize to -pi <= a < pi
p1.x = a/m_engine->GetHFovAngle() + 0.5f;
a = eyeDirV + planet.angle.y;
p1.y = 0.4f+(Math::Mod(a+Math::PI, Math::PI*2.0f)-Math::PI)*(2.0f/Math::PI);

View File

@ -518,6 +518,8 @@ void CPlayerProfile::LoadScene(std::string dir)
CLevelParserLine* line = levelParser.Get("Mission");
cat = GetLevelCategoryFromDir(line->GetParam("base")->AsString());
if (dir == "../../crashsave") LoadFinishedLevels(cat);
rank = line->GetParam("rank")->AsInt();
if (cat == LevelCategory::CustomLevels)
{

View File

@ -125,9 +125,6 @@ const Gfx::Color COLOR_REF_ALIEN = Gfx::Color(135.0f/256.0f, 170.0f/256.0f, 13.
const Gfx::Color COLOR_REF_GREEN = Gfx::Color(135.0f/256.0f, 170.0f/256.0f, 13.0f/256.0f); // green
const Gfx::Color COLOR_REF_WATER = Gfx::Color( 25.0f/256.0f, 255.0f/256.0f, 240.0f/256.0f); // cyan
template<> CRobotMain* CSingleton<CRobotMain>::m_instance = nullptr;
//! Constructor of robot application
CRobotMain::CRobotMain()
{
@ -971,33 +968,25 @@ bool CRobotMain::ProcessEvent(Event &event)
{
StartDisplayVisit(EVENT_NULL);
}
if (data->slot == INPUT_SLOT_SPEED05)
if (data->slot == INPUT_SLOT_SPEED_DEC)
{
SetSpeed(0.5f);
SetSpeed(GetSpeed()*0.5f);
}
if (data->slot == INPUT_SLOT_SPEED10)
if (data->slot == INPUT_SLOT_SPEED_RESET)
{
SetSpeed(1.0f);
}
if (data->slot == INPUT_SLOT_SPEED15)
if (data->slot == INPUT_SLOT_SPEED_INC)
{
SetSpeed(1.5f);
SetSpeed(GetSpeed()*2.0f);
}
if (data->slot == INPUT_SLOT_SPEED20)
if (data->slot == INPUT_SLOT_QUICKSAVE)
{
SetSpeed(2.0f);
QuickSave();
}
if (data->slot == INPUT_SLOT_SPEED30)
if (data->slot == INPUT_SLOT_QUICKLOAD)
{
SetSpeed(3.0f);
}
if (data->slot == INPUT_SLOT_SPEED40)
{
SetSpeed(4.0f);
}
if (data->slot == INPUT_SLOT_SPEED60)
{
SetSpeed(6.0f);
QuickLoad();
}
if (data->key == KEY(c) && ((event.kmodState & KEY_MOD(CTRL)) != 0) && m_engine->GetShowStats())
{
@ -2307,37 +2296,7 @@ void CRobotMain::InitEye()
//! Advances the entire scene
bool CRobotMain::EventFrame(const Event &event)
{
// TODO: For some reason we're getting one big event with event.rTime > 0.1f after loading before the movie starts?
if (!m_immediatSatCom && !m_beginSatCom && !m_movieLock &&
m_gameTime > 0.1f && m_phase == PHASE_SIMUL)
{
m_displayText->DisplayError(INFO_BEGINSATCOM, Math::Vector(0.0f,0.0f,0.0f));
m_beginSatCom = true; // message appears
}
m_time += event.rTime;
if (!m_movieLock && !m_pause->IsPauseType(PAUSE_ENGINE))
{
m_gameTime += event.rTime;
m_gameTimeAbsolute += m_app->GetRealRelTime() / 1e9f;
}
if (!m_movieLock && !m_pause->IsPauseType(PAUSE_ENGINE) && m_missionTimerStarted)
m_missionTimer += event.rTime;
if (!m_pause->IsPauseType(PAUSE_ENGINE) && m_autosave && m_gameTimeAbsolute >= m_autosaveLast+(m_autosaveInterval*60) && m_phase == PHASE_SIMUL)
{
if (m_levelCategory == LevelCategory::Missions ||
m_levelCategory == LevelCategory::FreeGame ||
m_levelCategory == LevelCategory::CustomLevels )
{
if (!IOIsBusy() && m_missionType != MISSION_CODE_BATTLE)
{
m_autosaveLast = m_gameTimeAbsolute;
Autosave();
}
}
}
m_water->EventProcess(event);
m_cloud->EventProcess(event);
@ -2422,6 +2381,40 @@ bool CRobotMain::EventFrame(const Event &event)
if (toto != nullptr)
dynamic_cast<CInteractiveObject*>(toto)->EventProcess(event);
// NOTE: m_movieLock is set only after the first update of CAutoBase finishes
if (m_phase == PHASE_SIMUL)
{
if (!m_immediatSatCom && !m_beginSatCom && !m_movieLock)
{
m_displayText->DisplayError(INFO_BEGINSATCOM, Math::Vector(0.0f, 0.0f, 0.0f));
m_beginSatCom = true; // message appears
}
if (!m_pause->IsPauseType(PAUSE_ENGINE) && !m_movieLock)
{
m_gameTime += event.rTime;
m_gameTimeAbsolute += m_app->GetRealRelTime() / 1e9f;
if (m_missionTimerStarted)
m_missionTimer += event.rTime;
if (m_autosave && m_gameTimeAbsolute >= m_autosaveLast + (m_autosaveInterval * 60))
{
if (m_levelCategory == LevelCategory::Missions ||
m_levelCategory == LevelCategory::FreeGame ||
m_levelCategory == LevelCategory::CustomLevels)
{
if (!IOIsBusy() && m_missionType != MISSION_CODE_BATTLE)
{
m_autosaveLast = m_gameTimeAbsolute;
Autosave();
}
}
}
}
}
HiliteFrame(event.rTime);
// Moves the film indicator.
@ -3648,12 +3641,13 @@ void CRobotMain::CreateScene(bool soluce, bool fixScene, bool resetObject)
throw CLevelParserException("Unknown command: '" + line->GetCommand() + "' in " + line->GetLevelFilename() + ":" + boost::lexical_cast<std::string>(line->GetLineNumber()));
}
// Do this here to prevent the first frame from taking a long time to render
m_engine->UpdateGroundSpotTextures();
m_ui->GetLoadingScreen()->SetProgress(1.0f, RT_LOADING_FINISHED);
if (m_ui->GetLoadingScreen()->IsVisible())
{
// Force render of the "Loading finished" screen
// TODO: For some reason, rendering of the first frame after the simulation starts is very slow
// We're doing this because it looks weird when the progress bar is finished but it still says "Loading programs"
// Force render of the "Loading finished" screen because it looks weird when the progress bar disappears in the middle
m_app->Render();
}
@ -3695,7 +3689,7 @@ void CRobotMain::CreateScene(bool soluce, bool fixScene, bool resetObject)
// TODO: m_engine->TimeInit(); ??
m_input->ResetKeyStates();
m_time = 0.0f;
m_gameTime = 0.0f;
if (m_sceneReadPath.empty()) m_gameTime = 0.0f;
m_gameTimeAbsolute = 0.0f;
m_autosaveLast = 0.0f;
m_infoUsed = 0;
@ -4548,6 +4542,7 @@ bool CRobotMain::IOWriteScene(std::string filename, std::string filecbot, std::s
else
line->AddParam("chap", MakeUnique<CLevelParserParam>(m_levelChap));
line->AddParam("rank", MakeUnique<CLevelParserParam>(m_levelRank));
line->AddParam("gametime", MakeUnique<CLevelParserParam>(GetGameTime()));
levelParser.AddLine(std::move(line));
line = MakeUnique<CLevelParserLine>("Map");
@ -4728,6 +4723,9 @@ CObject* CRobotMain::IOReadScene(std::string filename, std::string filecbot)
int objCounter = 0;
for (auto& line : levelParser.GetLines())
{
if (line->GetCommand() == "Mission")
m_gameTime = line->GetParam("gametime")->AsFloat(0.0f);
if (line->GetCommand() == "Map")
m_map->ZoomMap(line->GetParam("zoom")->AsFloat());
@ -5563,6 +5561,31 @@ void CRobotMain::Autosave()
m_playerProfile->SaveScene(dir, info);
}
void CRobotMain::QuickSave()
{
GetLogger()->Info("Quicksave!\n");
char infostr[100];
time_t now = time(nullptr);
strftime(infostr, 99, "%y.%m.%d %H:%M", localtime(&now));
std::string info = std::string("[QUICKSAVE]") + infostr;
std::string dir = m_playerProfile->GetSaveFile(std::string("quicksave"));
m_playerProfile->SaveScene(dir, info);
}
void CRobotMain::QuickLoad()
{
std::string dir = m_playerProfile->GetSaveFile(std::string("quicksave"));
if(!CResourceManager::Exists(dir))
{
m_displayText->DisplayError(ERR_NO_QUICK_SLOT, Math::Vector(0.0f,0.0f,0.0f), 15.0f, 60.0f, 1000.0f);
GetLogger()->Debug("Quicksave slot not found\n");
return;
}
m_playerProfile->LoadScene(dir);
}
void CRobotMain::SetExitAfterMission(bool exit)
{
m_exitAfterMission = exit;
@ -5824,6 +5847,7 @@ void CRobotMain::CreateCodeBattleInterface()
pw->CreateButton(pos, ddim, 13, EVENT_CODE_BATTLE_SPECTATOR);
}
if (!m_scoreboard) return;
pos.y += ddim.y;
ddim.y = textHeight;
int i = 0;

View File

@ -510,6 +510,8 @@ protected:
void AutosaveRotate();
void Autosave();
void QuickSave();
void QuickLoad();
bool DestroySelectedObject();
void PushToSelectionHistory(CObject* obj);
CObject* PopFromSelectionHistory();

View File

@ -405,12 +405,12 @@ bool CAutoFactory::EventProcess(const Event &event)
{
Program* program = dynamic_cast<CProgramStorageObject*>(vehicle)->AddProgram();
if (boost::regex_search(m_program, boost::regex("^[A-Za-z0-9_]+$"))) // Public function name?
if (boost::regex_match(m_program, boost::regex("[A-Za-z0-9_]+"))) // Public function name?
{
std::string code = "extern void object::Start_"+m_program+"()\n{\n\t\n\t//Automatically generated by object.factory()\n\t"+m_program+"();\n\t\n}\n";
program->script->SendScript(code.c_str());
}
else if (boost::regex_search(m_program, boost::regex("\\.txt$"))) // File name (with .txt extension)?
else if (boost::regex_match(m_program, boost::regex(".*\\.txt"))) // File name (with .txt extension)?
{
program->script->ReadScript(m_program.c_str());
}

View File

@ -59,4 +59,11 @@ public:
//! Damage the object, with the given force. Returns true if the object has been fully destroyed (assuming the object is destroyable, of course). If force == infinity, destroy immediately (this is the default value)
/** NOTE: You should never assume that after this function exits, the object is destroyed, unless it returns true. Even if you specify force = infinity, if may still sometimes decide not to destroy the object. */
virtual bool DamageObject(DamageType type, float force = std::numeric_limits<float>::infinity(), CObject* killer = nullptr) = 0;
//! Set the status that means the object is currently taking damage
virtual void SetDamaging(bool damaging) = 0;
//! Is object currently taking damage?
virtual bool IsDamaging() = 0;
};

View File

@ -1783,6 +1783,7 @@ bool CMotionVehicle::EventFrameCanoni(const Event &event)
float energy = GetObjectEnergyLevel(m_object);
if (energy == 0.0f) return true;
if (energy > 1.0f) energy = 1.0f; //fix issue with cheated cells, see issue #1009
factor = 0.5f+energy*0.5f;
if ( bOnBoard ) factor *= 0.8f;

View File

@ -36,10 +36,6 @@
#include <algorithm>
template<> CObjectManager* CSingleton<CObjectManager>::m_instance = nullptr;
CObjectManager::CObjectManager(Gfx::CEngine* engine,
Gfx::CTerrain* terrain,
Gfx::COldModelManager* oldModelManager,

View File

@ -137,6 +137,7 @@ COldObject::COldObject(int id)
m_bVirusMode = false;
m_virusTime = 0.0f;
m_lastVirusParticle = 0.0f;
m_damaging = false;
m_dying = DeathType::Alive;
m_bFlat = false;
m_gunGoalV = 0.0f;
@ -387,6 +388,14 @@ bool COldObject::DamageObject(DamageType type, float force, CObject* killer)
float shield = GetShield();
shield -= loss;
SetShield(shield);
// Sending info about taking damage
if (!m_damaging)
{
SetDamaging(true);
m_main->UpdateShortcuts();
}
m_damageTime = m_time;
}
else
{
@ -394,6 +403,7 @@ bool COldObject::DamageObject(DamageType type, float force, CObject* killer)
{
// Dead immediately
SetShield(0.0f);
SetDamaging(false);
}
}
dead = (GetShield() <= 0.0f);
@ -424,7 +434,6 @@ bool COldObject::DamageObject(DamageType type, float force, CObject* killer)
{
m_engine->GetPyroManager()->Create(Gfx::PT_SHOTT, this, loss);
}
return false;
}
@ -440,6 +449,7 @@ void COldObject::DestroyObject(DestructionType type, CObject* killer)
if (Implements(ObjectInterfaceType::Shielded))
{
SetShield(0.0f);
SetDamaging(false);
}
Gfx::PyroType pyroType = Gfx::PT_NULL;
@ -1010,6 +1020,8 @@ void COldObject::Write(CLevelParserLine* line)
if ( m_virusTime != 0.0f )
line->AddParam("virusTime", MakeUnique<CLevelParserParam>(m_virusTime));
line->AddParam("lifetime", MakeUnique<CLevelParserParam>(m_aTime));
// Sets the parameters of the command line.
CLevelParserParamVec cmdline;
for(float value : GetCmdLine())
@ -1144,6 +1156,8 @@ void COldObject::Read(CLevelParserLine* line)
m_bVirusMode = line->GetParam("virusMode")->AsBool(false);
m_virusTime = line->GetParam("virusTime")->AsFloat(0.0f);
m_aTime = line->GetParam("lifetime")->AsFloat(0.0f);
if ( m_motion != nullptr )
{
m_motion->Read(line);
@ -2148,6 +2162,12 @@ bool COldObject::EventFrame(const Event &event)
SetShield(GetShield() + event.rTime*(1.0f/GetShieldFullRegenTime()));
}
if (m_damaging && m_time - m_damageTime > 2.0f)
{
SetDamaging(false);
m_main->UpdateShortcuts();
}
return true;
}
@ -2652,6 +2672,15 @@ float COldObject::GetMagnifyDamage()
return m_magnifyDamage;
}
void COldObject::SetDamaging(bool damaging)
{
m_damaging = damaging;
}
bool COldObject::IsDamaging()
{
return m_damaging;
}
void COldObject::SetDying(DeathType deathType)
{

View File

@ -237,6 +237,9 @@ public:
void SetMagnifyDamage(float factor) override;
float GetMagnifyDamage() override;
void SetDamaging(bool damaging);
bool IsDamaging() override;
void SetDying(DeathType deathType) override;
DeathType GetDying() override;
bool IsDying() override;
@ -356,6 +359,8 @@ protected:
bool m_bSelectable; // selectable object
bool m_bCheckToken; // object with audited tokens
bool m_underground; // object active but undetectable
bool m_damaging;
float m_damageTime;
DeathType m_dying;
bool m_bFlat;
bool m_bTrainer; // drive vehicle (without remote)

View File

@ -803,7 +803,8 @@ Error CTaskGoto::Start(Math::Vector goal, float altitude,
Error CTaskGoto::IsEnded()
{
Math::Vector pos;
float limit, angle = 0.0f, dist, h, level;
float limit, angle = 0.0f, h, level;
volatile float dist; //fix for issue #844
if ( m_engine->GetPause() ) return ERR_CONTINUE;
if ( m_error != ERR_OK ) return m_error;
@ -916,7 +917,9 @@ Error CTaskGoto::IsEnded()
if ( m_goalMode == TGG_EXPRESS )
{
dist = Math::DistanceProjected(m_goal, pos);
if ( dist < 10.0f && dist > m_lastDistance )
float margin = 10.0f;
if ( m_object->Implements(ObjectInterfaceType::Flying) ) margin = 20.0f;
if ( dist < margin && dist > m_lastDistance )
{
return ERR_STOP;
}

View File

@ -376,5 +376,5 @@ bool CTaskRecover::Abort()
CObject* CTaskRecover::SearchRuin()
{
return CObjectManager::GetInstancePointer()->FindNearest(nullptr, m_recoverPos, {OBJECT_RUINmobilew1, OBJECT_RUINmobilew2, OBJECT_RUINmobilet1, OBJECT_RUINmobilet2, OBJECT_RUINmobiler1, OBJECT_RUINmobiler2}, 40.0f/g_unit);
return CObjectManager::GetInstancePointer()->FindNearest(nullptr, m_recoverPos, {OBJECT_RUINmobilew1, OBJECT_RUINmobilew2, OBJECT_RUINmobilet1, OBJECT_RUINmobilet2, OBJECT_RUINmobiler1, OBJECT_RUINmobiler2, OBJECT_RUINdoor, OBJECT_RUINsupport, OBJECT_RUINradar}, 40.0f/g_unit);
}

View File

@ -363,13 +363,110 @@ bool CTaskTerraform::Terraform()
type = pObj->GetType();
if ( type == OBJECT_NULL ) continue;
if ( type == OBJECT_TEEN34 ) // stone?
if ( type == OBJECT_TEEN34 ||
type == OBJECT_POWER ||
type == OBJECT_ATOMIC ||
type == OBJECT_STONE ||
type == OBJECT_URANIUM ||
type == OBJECT_METAL ||
type == OBJECT_BULLET ||
type == OBJECT_BBOX ||
type == OBJECT_KEYa ||
type == OBJECT_KEYb ||
type == OBJECT_KEYc ||
type == OBJECT_KEYd ||
type == OBJECT_TNT ||
type == OBJECT_NEST ||
type == OBJECT_BOMB ||
type == OBJECT_PLANT0 ||
type == OBJECT_PLANT1 ||
type == OBJECT_PLANT2 ||
type == OBJECT_PLANT3 ||
type == OBJECT_PLANT4 ||
type == OBJECT_PLANT5 ||
type == OBJECT_PLANT6 ||
type == OBJECT_PLANT7 ||
type == OBJECT_PLANT15 ||
type == OBJECT_PLANT16 ||
type == OBJECT_PLANT17 ||
type == OBJECT_PLANT18 ||
type == OBJECT_PLANT19 ||
type == OBJECT_MUSHROOM1 ||
type == OBJECT_MUSHROOM2 ||
type == OBJECT_FACTORY ||
type == OBJECT_STATION ||
type == OBJECT_CONVERT ||
type == OBJECT_REPAIR ||
type == OBJECT_DESTROYER ||
type == OBJECT_ENERGY ||
type == OBJECT_LABO ||
type == OBJECT_PARA ||
type == OBJECT_START ||
type == OBJECT_END ||
type == OBJECT_EGG ||
type == OBJECT_RUINmobilew1 ||
type == OBJECT_RUINmobilew2 ||
type == OBJECT_RUINmobilet1 ||
type == OBJECT_RUINmobilet2 ||
type == OBJECT_RUINdoor ||
type == OBJECT_RUINsupport ||
type == OBJECT_RUINradar ||
type == OBJECT_BARRIER0 ||
type == OBJECT_APOLLO4 ) // almost everything?
{
dist = Math::Distance(m_terraPos, pObj->GetPosition());
if ( dist > 20.0f ) continue;
if (type == OBJECT_BULLET ||
type == OBJECT_NEST ||
type == OBJECT_EGG) // Alien Organic?
{
if ( dist > 5.0f ) continue;
m_engine->GetPyroManager()->Create(Gfx::PT_FRAGO, pObj);
}
else if (type == OBJECT_TNT ||
type == OBJECT_BOMB) // Explosives?
{
if ( dist > 5.0f ) continue;
m_engine->GetPyroManager()->Create(Gfx::PT_EXPLOT, pObj);
dynamic_cast<CDamageableObject*>(m_object)->DamageObject(DamageType::Explosive, 0.9f);
}
else if (type == OBJECT_PLANT0 ||
type == OBJECT_PLANT1 ||
type == OBJECT_PLANT2 ||
type == OBJECT_PLANT3 ||
type == OBJECT_PLANT4 ||
type == OBJECT_PLANT5 ||
type == OBJECT_PLANT6 ||
type == OBJECT_PLANT7 ||
type == OBJECT_PLANT15 ||
type == OBJECT_PLANT16 ||
type == OBJECT_PLANT17 ||
type == OBJECT_PLANT18 ||
type == OBJECT_PLANT19 ||
type == OBJECT_MUSHROOM1 ||
type == OBJECT_MUSHROOM2) // Plants?
{
if ( dist > 7.5f ) continue;
m_engine->GetPyroManager()->Create(Gfx::PT_EGG, pObj);
}
else if (type == OBJECT_FACTORY ||
type == OBJECT_STATION ||
type == OBJECT_CONVERT ||
type == OBJECT_REPAIR ||
type == OBJECT_DESTROYER ||
type == OBJECT_ENERGY ||
type == OBJECT_LABO ||
type == OBJECT_PARA) // Buildings?
{
if ( dist > 15.0f ) continue;
dynamic_cast<CDamageableObject*>(pObj)->DamageObject(DamageType::Explosive, 0.2f);
}
else // Other?
{
if ( dist > 5.0f ) continue;
m_engine->GetPyroManager()->Create(Gfx::PT_FRAGT, pObj);
}
}
else
{
if ( !pObj->Implements(ObjectInterfaceType::Movable) ) continue;
@ -388,6 +485,14 @@ bool CTaskTerraform::Terraform()
if (type == OBJECT_SPIDER) actionType = MSS_BACK1;
motion->SetAction(actionType, 0.8f+Math::Rand()*0.3f);
dynamic_cast<CBaseAlien*>(pObj)->SetFixed(true); // not moving
if ( dist > 5.0f ) continue;
m_engine->GetPyroManager()->Create(Gfx::PT_EXPLOO, pObj);
}
else if ( type == OBJECT_BEE || type == OBJECT_WORM )
{
if ( dist > 5.0f ) continue;
m_engine->GetPyroManager()->Create(Gfx::PT_EXPLOO, pObj);
}
}
}

View File

@ -109,7 +109,7 @@ Error CTaskTurn::IsEnded()
if ( m_bLeft )
{
if ( angle <= m_startAngle+m_angle )
if ( angle <= m_finalAngle )
{
m_physics->SetMotorSpeedZ(0.0f);
//? m_physics->SetCirMotionY(MO_MOTSPEED, 0.0f);
@ -118,10 +118,15 @@ Error CTaskTurn::IsEnded()
m_object->SetRotationY(m_finalAngle);
return ERR_STOP;
}
if ( !m_bDecel && angle <= m_startAngle+m_angle)
{
m_bDecel = true;
m_physics->SetMotorSpeedZ(-0.5f);
}
}
else
{
if ( angle >= m_startAngle+m_angle )
if ( angle >= m_finalAngle )
{
m_physics->SetMotorSpeedZ(0.0f);
//? m_physics->SetCirMotionY(MO_MOTSPEED, 0.0f);
@ -130,6 +135,11 @@ Error CTaskTurn::IsEnded()
m_object->SetRotationY(m_finalAngle);
return ERR_STOP;
}
if ( !m_bDecel && angle >= m_startAngle+m_angle)
{
m_bDecel = true;
m_physics->SetMotorSpeedZ(0.5f);
}
}
return ERR_CONTINUE;

View File

@ -41,4 +41,5 @@ protected:
float m_finalAngle = 0.0f;
bool m_bLeft = false;
bool m_bError = false;
bool m_bDecel = false;
};

View File

@ -271,6 +271,7 @@ std::string GetHelpFilename(const char *token)
if ( strcmp(token, "factory" ) == 0 ) helpfile = "cbot/factory";
if ( strcmp(token, "destroy" ) == 0 ) helpfile = "cbot/destroy";
if ( strcmp(token, "search" ) == 0 ) helpfile = "cbot/search";
if ( strcmp(token, "searchall" ) == 0 ) helpfile = "cbot/searchall";
if ( strcmp(token, "radar" ) == 0 ) helpfile = "cbot/radar";
if ( strcmp(token, "radarall" ) == 0 ) helpfile = "cbot/radarall";
if ( strcmp(token, "direction" ) == 0 ) helpfile = "cbot/direct";
@ -421,6 +422,7 @@ bool IsFunction(const char *token)
if ( strcmp(token, "takeoff" ) == 0 ) return true;
if ( strcmp(token, "destroy" ) == 0 ) return true;
if ( strcmp(token, "search" ) == 0 ) return true;
if ( strcmp(token, "searchall" ) == 0 ) return true;
if ( strcmp(token, "radar" ) == 0 ) return true;
if ( strcmp(token, "radarall" ) == 0 ) return true;
if ( strcmp(token, "detect" ) == 0 ) return true;
@ -522,7 +524,8 @@ const char* GetHelpText(const char *token)
if ( strcmp(token, "research" ) == 0 ) return "object.research ( type );";
if ( strcmp(token, "takeoff" ) == 0 ) return "object.takeoff ( );";
if ( strcmp(token, "destroy" ) == 0 ) return "object.destroy ( );";
if ( strcmp(token, "search" ) == 0 ) return "search ( cat, pos );";
if ( strcmp(token, "search" ) == 0 ) return "search ( cat, pos, min, max, sens, filter );";
if ( strcmp(token, "searchall" ) == 0 ) return "searchall ( cat, pos, min, max, sens, filter );";
if ( strcmp(token, "radar" ) == 0 ) return "radar ( cat, angle, focus, min, max, sens, filter );";
if ( strcmp(token, "radarall" ) == 0 ) return "radarall ( cat, angle, focus, min, max, sens, filter );";
if ( strcmp(token, "detect" ) == 0 ) return "detect ( cat );";

View File

@ -589,6 +589,56 @@ void CScript::UpdateList(Ui::CList* list)
list->SetState(Ui::STATE_ENABLE);
}
// Colorize a string literal with escape sequences also colored
void HighlightString(Ui::CEdit* edit, const std::string& s, int start)
{
edit->SetFormat(start, start + 1, Gfx::FONT_HIGHLIGHT_STRING);
auto it = s.cbegin() + 1;
++start;
while (it != s.cend() && *it != '\"')
{
if (*(it++) != '\\') // not escape sequence
{
edit->SetFormat(start, start + 1, Gfx::FONT_HIGHLIGHT_STRING);
++start;
continue;
}
if (it == s.cend()) break;
int end = start + 2;
if (CBot::CharInList(*it, "01234567")) // octal escape sequence
{
for (int i = 0; ++it != s.cend() && i < 2; i++, end++)
{
if (!CBot::CharInList(*it, "01234567")) break;
}
}
else if (*it == 'x' || *it == 'u' || *it == 'U') // hex or unicode escape
{
bool isHexCode = (*it == 'x');
int maxlen = (*it == 'u') ? 4 : 8;
for (int i = 0; ++it != s.cend(); i++, end++)
{
if (!isHexCode && i >= maxlen) break;
if (!CBot::CharInList(*it, "0123456789ABCDEFabcdef")) break;
}
}
else // n, r, t, etc.
++it;
edit->SetFormat(start, end, Gfx::FONT_HIGHLIGHT_NONE);
start = end;
}
if (it != s.cend())
edit->SetFormat(start, start + 1, Gfx::FONT_HIGHLIGHT_STRING);
}
// Colorize the text according to syntax.
@ -643,10 +693,16 @@ void CScript::ColorizeScript(Ui::CEdit* edit, int rangeStart, int rangeEnd)
{
color = Gfx::FONT_HIGHLIGHT_CONST;
}
else if (type == CBot::TokenTypString || type == CBot::TokenTypNum) // string literals and numbers
else if (type == CBot::TokenTypNum) // numbers
{
color = Gfx::FONT_HIGHLIGHT_STRING;
}
else if (type == CBot::TokenTypString) // string literals
{
HighlightString(edit, token, cursor1);
bt = bt->GetNext();
continue;
}
assert(cursor1 < cursor2);
edit->SetFormat(cursor1, cursor2, color);

View File

@ -79,9 +79,9 @@ CBotTypResult CScriptFunctions::cClassOneFloat(CBotVar* thisclass, CBotVar* &var
return cOneFloat(var, nullptr);
}
// Compiling a procedure with a "dot".
// Compile a parameter of type "point".
CBotTypResult CScriptFunctions::cPoint(CBotVar* &var, void* user)
CBotTypResult cPoint(CBotVar* &var, void* user)
{
if ( var == nullptr ) return CBotTypResult(CBotErrLowParam);
@ -695,48 +695,74 @@ bool CScriptFunctions::rDelete(CBotVar* var, CBotVar* result, int& exception, vo
CObjectManager::GetInstancePointer()->DeleteObject(obj);
}
}
return true;
// Returning "false" here makes sure the program doesn't try to keep executing if the robot just destroyed itself
// using delete(this.id)
// See issue #925
return false;
}
// Compilation of the instruction "search(type, pos)".
CBotTypResult CScriptFunctions::cSearch(CBotVar* &var, void* user)
CBotTypResult compileSearch(CBotVar* &var, void* user, CBotTypResult returnValue)
{
CBotVar* array;
CBotTypResult ret;
if ( var == nullptr ) return CBotTypResult(CBotErrLowParam);
if ( var->GetType() == CBotTypArrayPointer )
{
array = var->GetItemList();
if ( array == nullptr ) return CBotTypResult(CBotTypPointer);
if ( array->GetType() > CBotTypDouble ) return CBotTypResult(CBotErrBadNum);
CBotTypResult type = var->GetTypResult().GetTypElem();
if ( type.GetType() > CBotTypDouble ) return CBotTypResult(CBotErrBadParam); // type
}
else if ( var->GetType() > CBotTypDouble ) return CBotTypResult(CBotErrBadNum);
else if ( var->GetType() > CBotTypDouble ) return CBotTypResult(CBotErrBadNum); // type
var = var->GetNext();
if ( var != nullptr )
{
ret = cPoint(var, user);
if ( ret.GetType() != 0 ) return ret;
if ( var != nullptr ) return CBotTypResult(CBotErrOverParam);
}
return CBotTypResult(CBotTypPointer, "object");
if ( var == nullptr ) return returnValue;
CBotTypResult ret = cPoint(var, user); // pos
if ( ret.GetType() != 0 ) return ret;
if ( var == nullptr ) return returnValue;
if ( var->GetType() > CBotTypDouble ) return CBotTypResult(CBotErrBadNum); // min
var = var->GetNext();
if ( var == nullptr ) return returnValue;
if ( var->GetType() > CBotTypDouble ) return CBotTypResult(CBotErrBadNum); // max
var = var->GetNext();
if ( var == nullptr ) return returnValue;
if ( var->GetType() > CBotTypDouble ) return CBotTypResult(CBotErrBadNum); // sense
var = var->GetNext();
if ( var == nullptr ) return returnValue;
if ( var->GetType() > CBotTypDouble ) return CBotTypResult(CBotErrBadNum); // filter
var = var->GetNext();
if ( var == nullptr ) return returnValue;
return CBotTypResult(CBotErrOverParam);
}
// Instruction "search(type, pos)".
// Compilation of "search(type, pos, min, max, sens, filter)".
bool CScriptFunctions::rSearch(CBotVar* var, CBotVar* result, int& exception, void* user)
CBotTypResult CScriptFunctions::cSearch(CBotVar* &var, void* user)
{
CObject* pThis = static_cast<CScript*>(user)->m_object;
CObject *pBest;
CBotVar* array;
Math::Vector pos, oPos;
bool bArray;
int type;
return compileSearch(var, user, CBotTypResult(CBotTypPointer, "object"));
}
CBotTypResult CScriptFunctions::cSearchAll(CBotVar* &var, void* user)
{
return compileSearch(var, user, CBotTypResult(CBotTypArrayPointer, CBotTypResult(CBotTypPointer, "object")));
}
bool runSearch(CBotVar* var, Math::Vector pos, int& exception, std::function<bool(std::vector<ObjectType>, Math::Vector, float, float, bool, RadarFilter)> code)
{
CBotVar* array;
RadarFilter filter;
float minDist, maxDist, sens;
int type;
bool bArray = false;
type = OBJECT_NULL;
array = nullptr;
minDist = 0.0f*g_unit;
maxDist = 1000.0f*g_unit;
sens = 1.0f;
filter = FILTER_NONE;
if ( var != nullptr )
{
if ( var->GetType() == CBotTypArrayPointer )
{
array = var->GetItemList();
@ -747,14 +773,35 @@ bool CScriptFunctions::rSearch(CBotVar* var, CBotVar* result, int& exception, vo
type = var->GetValInt();
bArray = false;
}
var = var->GetNext();
if ( var != nullptr )
{
if ( !GetPoint(var, exception, pos) ) return true;
}
else
if ( !GetPoint(var, exception, pos) ) return false;
if ( var != nullptr )
{
pos = pThis->GetPosition();
minDist = var->GetValFloat();
var = var->GetNext();
if ( var != nullptr )
{
maxDist = var->GetValFloat();
var = var->GetNext();
if ( var != nullptr )
{
sens = var->GetValFloat();
var = var->GetNext();
if ( var != nullptr )
{
filter = static_cast<RadarFilter>(var->GetValInt());
}
}
}
}
}
}
std::vector<ObjectType> type_v;
@ -774,7 +821,16 @@ bool CScriptFunctions::rSearch(CBotVar* var, CBotVar* result, int& exception, vo
}
}
pBest = CObjectManager::GetInstancePointer()->Radar(pThis, pos, 0.0f, type_v, 0.0f, Math::PI*2.0f, 0.0f, 1000.0f, false, FILTER_NONE, true);
return code(type_v, pos, minDist, maxDist, sens < 0, filter);
}
bool CScriptFunctions::rSearch(CBotVar* var, CBotVar* result, int& exception, void* user)
{
CObject* pThis = static_cast<CScript*>(user)->m_object;
return runSearch(var, pThis->GetPosition(), exception, [&result, pThis](std::vector<ObjectType> types, Math::Vector pos, float minDist, float maxDist, bool furthest, RadarFilter filter)
{
CObject* pBest = CObjectManager::GetInstancePointer()->Radar(pThis, pos, 0.0f, types, 0.0f, Math::PI*2.0f, minDist, maxDist, furthest, filter, true);
if ( pBest == nullptr )
{
@ -786,6 +842,26 @@ bool CScriptFunctions::rSearch(CBotVar* var, CBotVar* result, int& exception, vo
}
return true;
});
}
bool CScriptFunctions::rSearchAll(CBotVar* var, CBotVar* result, int& exception, void* user)
{
CObject* pThis = static_cast<CScript*>(user)->m_object;
return runSearch(var, pThis->GetPosition(), exception, [&result, pThis](std::vector<ObjectType> types, Math::Vector pos, float minDist, float maxDist, bool furthest, RadarFilter filter)
{
std::vector<CObject*> best = CObjectManager::GetInstancePointer()->RadarAll(pThis, pos, 0.0f, types, 0.0f, Math::PI*2.0f, minDist, maxDist, furthest, filter, true);
int i = 0;
result->SetInit(CBotVar::InitType::DEF);
for (CObject* obj : best)
{
result->GetItem(i++, true)->SetPointer(obj->GetBotVar());
}
return true;
});
}
@ -2521,7 +2597,7 @@ CBotTypResult CScriptFunctions::cTopo(CBotVar* &var, void* user)
CBotTypResult ret;
if ( var == nullptr ) return CBotTypResult(CBotErrLowParam);
ret = CScriptFunctions::cPoint(var, user);
ret = cPoint(var, user);
if ( ret.GetType() != 0 ) return ret;
if ( var == nullptr ) return CBotTypResult(CBotTypFloat);
@ -3249,6 +3325,7 @@ void CScriptFunctions::Init()
CBotProgram::AddFunction("retobjectbyid", rGetObjectById, cGetObject);
CBotProgram::AddFunction("delete", rDelete, cDelete);
CBotProgram::AddFunction("search", rSearch, cSearch);
CBotProgram::AddFunction("searchall", rSearchAll, cSearchAll);
CBotProgram::AddFunction("radar", rRadar, cRadar);
CBotProgram::AddFunction("radarall", rRadarAll, cRadarAll);
CBotProgram::AddFunction("detect", rDetect, cDetect);

View File

@ -57,6 +57,7 @@ private:
static CBot::CBotTypResult cGetObject(CBot::CBotVar* &var, void* user);
static CBot::CBotTypResult cDelete(CBot::CBotVar* &var, void* user);
static CBot::CBotTypResult cSearch(CBot::CBotVar* &var, void* user);
static CBot::CBotTypResult cSearchAll(CBot::CBotVar* &var, void* user);
static CBot::CBotTypResult cRadar(CBot::CBotVar* &var, void* user);
static CBot::CBotTypResult cRadarAll(CBot::CBotVar* &var, void* user);
static CBot::CBotTypResult cDetect(CBot::CBotVar* &var, void* user);
@ -81,7 +82,6 @@ private:
static CBot::CBotTypResult cPenDown(CBot::CBotVar* &var, void* user);
static CBot::CBotTypResult cOnePoint(CBot::CBotVar* &var, void* user);
static CBot::CBotTypResult cPoint(CBot::CBotVar* &var, void* user);
static CBot::CBotTypResult cOneObject(CBot::CBotVar* &var, void* user);
static bool rEndMission(CBot::CBotVar* var, CBot::CBotVar* result, int& exception, void* user);
@ -97,6 +97,7 @@ private:
static bool rGetObject(CBot::CBotVar* var, CBot::CBotVar* result, int& exception, void* user);
static bool rDelete(CBot::CBotVar* var, CBot::CBotVar* result, int& exception, void* user);
static bool rSearch(CBot::CBotVar* var, CBot::CBotVar* result, int& exception, void* user);
static bool rSearchAll(CBot::CBotVar* var, CBot::CBotVar* result, int& exception, void* user);
static bool rRadar(CBot::CBotVar* var, CBot::CBotVar* result, int& exception, void* user);
static bool rRadarAll(CBot::CBotVar* var, CBot::CBotVar* result, int& exception, void* user);
static bool rDetect(CBot::CBotVar* var, CBot::CBotVar* result, int& exception, void* user);

View File

@ -57,7 +57,8 @@ enum ControlState
STATE_FRAME = (1<<13), // framework highlighting
STATE_WARNING = (1<<14), // framework hatched yellow / black
STATE_VALUE = (1<<15), // displays the value
STATE_RUN = (1<<16) // running program
STATE_RUN = (1<<16), // running program
STATE_DAMAGE = (1<<17) // taking damage
};

View File

@ -47,9 +47,9 @@
namespace Ui
{
const float MARGX = (5.0f/640.0f);
const float MARGY = (5.0f/480.0f);
const float MARGYS = (4.0f/480.0f);
const float MARGX = (3.75f/640.0f);
const float MARGY = (3.75f/480.0f);
const float MARGYS = (2.75f/480.0f);
const float MARGY1 = (1.0f/480.0f);
//! time limit for double-click
const float DELAY_DBCLICK = 0.75f;

View File

@ -207,6 +207,27 @@ void CShortcut::Draw()
uv2.x -= dp;
uv2.y -= dp;
DrawIcon(m_pos, m_dim, uv1, uv2);
}
if ( (m_state & STATE_DAMAGE) && Math::Mod(m_time, 0.7f) >= 0.3f )
{
Math::Point uv1, uv2;
float dp;
m_engine->SetTexture("textures/interface/button2.png");
m_engine->SetState(Gfx::ENG_RSTATE_TTEXTURE_BLACK);
uv1.x = 159.0f/256.0f;
uv1.y = 240.0f/256.0f;
uv2.x = 145.0f/256.0f;
uv2.y = 256.0f/256.0f;
dp = 0.5f/256.0f;
uv1.x += dp;
uv1.y += dp;
uv2.x -= dp;
uv2.y -= dp;
DrawIcon(m_pos, m_dim, uv1, uv2);
}
}

View File

@ -247,6 +247,7 @@ bool CMainShort::UpdateShortcuts()
assert(m_shortcuts[i]->Implements(ObjectInterfaceType::Controllable));
pc->SetState(STATE_CHECK, dynamic_cast<CControllableObject*>(m_shortcuts[i])->GetSelect());
pc->SetState(STATE_RUN, m_shortcuts[i]->Implements(ObjectInterfaceType::Programmable) && dynamic_cast<CProgrammableObject*>(m_shortcuts[i])->IsProgram());
pc->SetState(STATE_DAMAGE, dynamic_cast<CDamageableObject*>(m_shortcuts[i])->IsDamaging());
}
}
return true;

View File

@ -249,16 +249,16 @@ bool CStudio::EventProcess(const Event &event)
{
m_editActualPos = m_editFinalPos = pw->GetPos();
m_editActualDim = m_editFinalDim = pw->GetDim();
m_settings->SetWindowPos(m_editActualPos);
m_settings->SetWindowDim(m_editActualDim);
m_windowPos = m_editActualPos;
m_windowDim = m_editActualDim;
AdjustEditScript();
}
if ( event.type == pw->GetEventTypeReduce() )
{
if ( m_bEditMinimized )
{
m_editFinalPos = m_settings->GetWindowPos();
m_editFinalDim = m_settings->GetWindowDim();
m_editFinalPos = m_windowPos;
m_editFinalDim = m_windowDim;
m_bEditMinimized = false;
m_bEditMaximized = false;
}
@ -283,8 +283,8 @@ bool CStudio::EventProcess(const Event &event)
{
if ( m_bEditMaximized )
{
m_editFinalPos = m_settings->GetWindowPos();
m_editFinalDim = m_settings->GetWindowDim();
m_editFinalPos = m_windowPos;
m_editFinalDim = m_windowDim;
m_bEditMinimized = false;
m_bEditMaximized = false;
}
@ -579,8 +579,27 @@ void CStudio::StartEditScript(CScript *script, std::string name, Program* progra
pw = static_cast<CWindow*>(m_interface->SearchControl(EVENT_WINDOW6));
if (pw != nullptr) pw->ClearState(STATE_VISIBLE | STATE_ENABLE);
pos = m_editFinalPos = m_editActualPos = m_settings->GetWindowPos();
dim = m_editFinalDim = m_editActualDim = m_settings->GetWindowDim();
m_dialogPos = m_settings->GetIOPos();
m_dialogDim = m_settings->GetIODim();
m_windowPos = m_settings->GetWindowPos();
m_windowDim = m_settings->GetWindowDim();
m_bEditMaximized = m_settings->GetWindowMax();
if ( m_bEditMaximized )
{
m_editFinalPos.x = 0.00f;
m_editFinalPos.y = 0.00f;
m_editFinalDim.x = 1.00f;
m_editFinalDim.y = 1.00f;
}
else
{
m_editFinalPos = m_windowPos;
m_editFinalDim = m_windowDim;
}
pos = m_editActualPos = m_editFinalPos;
dim = m_editActualDim = m_editFinalDim;
pw = m_interface->CreateWindows(pos, dim, 8, EVENT_WINDOW3);
if (pw == nullptr)
return;
@ -597,6 +616,8 @@ void CStudio::StartEditScript(CScript *script, std::string name, Program* progra
pw->SetMinDim(Math::Point(0.49f, 0.50f));
pw->SetMaximized(m_bEditMaximized);
pw->SetMinimized(m_bEditMinimized);
// stop camera control if maximized
m_main->SetEditFull(m_bEditMaximized);
edit = pw->CreateEdit(pos, dim, 0, EVENT_STUDIO_EDIT);
@ -910,6 +931,12 @@ bool CStudio::StopEditScript(bool closeWithErrors)
m_runningPause = nullptr;
m_main->SetEditLock(false, true);
m_camera->SetType(m_editCamera);
m_settings->SetIOPos(m_dialogPos);
m_settings->SetIODim(m_dialogDim);
m_settings->SetWindowPos(m_windowPos);
m_settings->SetWindowDim(m_windowDim);
m_settings->SetWindowMax(m_bEditMaximized);
return true;
}
@ -1249,8 +1276,8 @@ void CStudio::AdjustDialog()
pw = static_cast< CWindow* >(m_interface->SearchControl(EVENT_WINDOW9));
if ( pw == nullptr ) return;
wpos = pw->GetPos();
wdim = pw->GetDim();
m_dialogPos = wpos = pw->GetPos();
m_dialogDim = wdim = pw->GetDim();
pw->SetPos(wpos); // to move the buttons on the titlebar
if ( m_dialog == SD_OPEN ||
@ -1300,10 +1327,9 @@ void CStudio::AdjustDialog()
pe->SetPos(ppos);
pe->SetDim(ddim);
nch = static_cast< int >((ddim.x*640.0f-22.0f)/8.0f);
name = pe->GetText(100);
nch = static_cast< int >((ddim.x*640.0f-22.0f)/5.75f);
name = pe->GetText(nch); // truncates the text according to max
pe->SetMaxChar(nch);
name[nch] = 0; // truncates the text according to max
pe->SetText(name);
}
@ -1361,19 +1387,10 @@ void CStudio::AdjustDialog()
bool CStudio::EventDialog(const Event &event)
{
CWindow* pw;
Math::Point wpos, wdim;
pw = static_cast< CWindow* >(m_interface->SearchControl(EVENT_WINDOW9));
if ( pw == nullptr ) return false;
if ( event.type == EVENT_WINDOW9 ) // window is moved?
{
wpos = pw->GetPos();
wdim = pw->GetDim();
m_settings->SetIOPos(wpos);
m_settings->SetIODim(wdim);
AdjustDialog();
return true;
}
if ( m_dialog == SD_OPEN ||
@ -1418,6 +1435,9 @@ bool CStudio::EventDialog(const Event &event)
return true;
}
CWindow* pw = static_cast< CWindow* >(m_interface->SearchControl(EVENT_WINDOW9));
if ( pw == nullptr ) return false;
if ( event.type == EVENT_DIALOG_CANCEL ||
(event.type == EVENT_KEY_DOWN && event.GetData<KeyEventData>()->key == KEY(ESCAPE)) ||
event.type == pw->GetEventTypeClose() )

View File

@ -108,6 +108,10 @@ protected:
Math::Point m_editActualDim;
Math::Point m_editFinalPos;
Math::Point m_editFinalDim;
Math::Point m_windowPos;
Math::Point m_windowDim;
Math::Point m_dialogPos;
Math::Point m_dialogDim;
float m_time;
float m_fixInfoTextTime;

View File

@ -1533,6 +1533,120 @@ TEST_F(CBotUT, String)
" ASSERT(c == \"Colobot!\");\n"
"}\n"
);
ExecuteTest(
"extern void MissingEndQuote()\n"
"{\n"
" \"Colobot...\n"
"}\n",
CBotErrEndQuote
);
}
TEST_F(CBotUT, StringEscapeCodes)
{
ExecuteTest(
"extern void HexEscapeCodes()\n"
"{\n"
" ASSERT(\" \\x07 \" == \" \\a \");\n"
" ASSERT(\" \\x08 \" == \" \\b \");\n"
" ASSERT(\" \\x09 \" == \" \\t \");\n"
" ASSERT(\" \\x0A \" == \" \\n \");\n"
" ASSERT(\" \\x0B \" == \" \\v \");\n"
" ASSERT(\" \\x0C \" == \" \\f \");\n"
" ASSERT(\" \\x0D \" == \" \\r \");\n"
" ASSERT(\" \\x22 \" == \" \\\" \");\n"
" ASSERT(\" \\x27 \" == \" \\\' \");\n"
" ASSERT(\" \\x5C \" == \" \\\\ \");\n"
" string test = \"\\x31 \\x32 \\x33\";\n"
" ASSERT(test == \"1 2 3\");\n"
"}\n"
"extern void OctalEscapeCodes()\n"
"{\n"
" ASSERT(\" \\000 \" == \" \\x00 \");\n"
" ASSERT(\" \\007 \" == \" \\x07 \");\n"
" ASSERT(\" \\010 \" == \" \\x08 \");\n"
" ASSERT(\" \\011 \" == \" \\x09 \");\n"
" ASSERT(\" \\012 \" == \" \\x0A \");\n"
" ASSERT(\" \\013 \" == \" \\x0B \");\n"
" ASSERT(\" \\014 \" == \" \\x0C \");\n"
" ASSERT(\" \\015 \" == \" \\x0D \");\n"
" ASSERT(\" \\042 \" == \" \\x22 \");\n"
" ASSERT(\" \\047 \" == \" \\x27 \");\n"
" ASSERT(\" \\134 \" == \" \\x5C \");\n"
" string test = \"\\101 \\102 \\103\";\n"
" ASSERT(test == \"A B C\");\n"
"}\n"
"extern void UnicodeEscapeCodesToUTF_8()\n"
"{\n"
" ASSERT(\" \\u0000 \" == \" \\0 \");\n"
" ASSERT(\" \\u0007 \" == \" \\a \");\n"
" ASSERT(\" \\u0008 \" == \" \\b \");\n"
" ASSERT(\" \\u0009 \" == \" \\t \");\n"
" ASSERT(\" \\u000A \" == \" \\n \");\n"
" ASSERT(\" \\u000B \" == \" \\v \");\n"
" ASSERT(\" \\u000C \" == \" \\f \");\n"
" ASSERT(\" \\u000D \" == \" \\r \");\n"
" ASSERT(\" \\u0022 \" == \" \\\" \");\n"
" ASSERT(\" \\u0027 \" == \" \\\' \");\n"
" ASSERT(\" \\u005C \" == \" \\\\ \");\n"
"\n"
" ASSERT(\"\\u00A9\" == \"\\xC2\\xA9\");\n"
" ASSERT(\"\\u00AE\" == \"\\xC2\\xAE\");\n"
" ASSERT(\"\\u262E\" == \"\\xE2\\x98\\xAE\");\n"
" ASSERT(\"\\u262F\" == \"\\xE2\\x98\\xAF\");\n"
" ASSERT(\"\\U0001F60E\" == \"\\xF0\\x9F\\x98\\x8E\");\n"
" ASSERT(\"\\U0001F61C\" == \"\\xF0\\x9F\\x98\\x9C\");\n"
" ASSERT(\"\\U0001F6E0\" == \"\\xF0\\x9F\\x9B\\xA0\");\n"
"}\n"
"extern void UnicodeMaxCharacterNameToUTF_8()\n"
"{\n"
" ASSERT(\"\\U0010FFFF\" == \"\\xF4\\x8F\\xBF\\xBF\");\n"
"}\n"
);
}
TEST_F(CBotUT, StringEscapeCodeErrors)
{
ExecuteTest(
"extern void UnknownEscapeSequence()\n"
"{\n"
" \"Unknown: \\p \";\n"
"}\n",
CBotErrBadEscape
);
ExecuteTest(
"extern void MissingHexDigits()\n"
"{\n"
" \" \\x \";\n"
"}\n",
CBotErrHexDigits
);
ExecuteTest(
"extern void HexValueOutOfRange()\n"
"{\n"
" \" \\x100 \";\n"
"}\n",
CBotErrHexRange
);
ExecuteTest(
"extern void OctalValueOutOfRange()\n"
"{\n"
" \" \\400 \";\n"
"}\n",
CBotErrOctalRange
);
ExecuteTest(
"extern void BadUnicodeCharacterName()\n"
"{\n"
" \" \\U00110000 \";\n"
"}\n",
CBotErrUnicodeName
);
}
// TODO: not implemented, see issue #694

111
tools/release.py Normal file → Executable file
View File

@ -1,9 +1,10 @@
#!/usr/bin/env python3
# Script to use when releasing new versions
# Run from main repo directory with data submodule pulled in data/
#
# Note: this has not yet been tested thoughtly, VERIFY EVERYTHING THIS SCRIPT DOES MANUALLY
#
# Will automatically:
# * Make sure you don't have any uncommited local changes
# * Make sure you don't forget to pull any changes before you start
# * Get current version number from CMakeLists.txt
# * Merge dev -> master in the data submodule
@ -13,26 +14,48 @@
# * Bump version number in main repo
# * Tag release in main repo
# * Update dev in main repo to point to the new merge commit
# * Push everything to remote
# * Create release drafts on GitHub
#
# After finished, verify everything is correct and push the changes
import os
import re
import sys
import subprocess
import io
try:
git_root = subprocess.check_output(['git', 'rev-parse', '--show-toplevel']).strip()
except subprocess.CalledProcessError:
print('\033[1;31m[!] Not inside a git repository!\033[0m')
sys.exit(1)
os.chdir(git_root)
while not os.path.isdir('.git'):
# Likely inside a submodule
# TODO: There is a command called `git rev-parse --show-superproject-working-tree` but it's quite new so not always available :/
os.chdir('..')
print('\033[1;34m[*] Make sure you don\'t have any uncommited local changes...\033[0m')
if subprocess.check_output(['git', 'status', '--porcelain']): # This also handles data subdirectory automatically
print('\033[1;31m[!] You have uncommited local changes!\033[0m')
os.system('git status') # Show the changes
sys.exit(1)
print('\033[1;34m[*] Make sure all remote changes are pulled...\033[0m')
os.system('git checkout dev')
os.system('git pull --ff')
os.system('git checkout master')
os.system('git pull --ff')
subprocess.check_call(['git', 'checkout', 'dev'])
subprocess.check_call(['git', 'pull', '--ff'])
subprocess.check_call(['git', 'checkout', 'master'])
subprocess.check_call(['git', 'pull', '--ff'])
os.chdir('data')
os.system('git checkout dev')
os.system('git pull --ff')
os.system('git checkout master')
os.system('git pull --ff')
subprocess.check_call(['git', 'checkout', 'dev'])
subprocess.check_call(['git', 'pull', '--ff'])
subprocess.check_call(['git', 'checkout', 'master'])
subprocess.check_call(['git', 'pull', '--ff'])
os.chdir('..')
print('\033[1;34m[*] Get version numbers...\033[0m')
os.system('git checkout dev')
subprocess.check_call(['git', 'checkout', 'dev'])
major = None
minor = None
revision = None
@ -40,7 +63,7 @@ codename = None
data = open('CMakeLists.txt', 'r').readlines()
for i in range(len(data)):
m = re.match(r'^set\(COLOBOT_VERSION_(MAJOR|MINOR|REVISION)( +)([0-9])+\)$', data[i])
m = re.match(r'^set\(COLOBOT_VERSION_(MAJOR|MINOR|REVISION)( +)([0-9]+)\)$', data[i])
if m:
x = int(m.group(3))
if m.group(1) == 'MAJOR':
@ -60,43 +83,79 @@ for i in range(len(data)):
codename = m.group(4)
data[i] = ('#' if comment else '')+'set(COLOBOT_VERSION_'+m.group(2)+m.group(3)+'"'+m.group(4)+'")\n'
os.system('git checkout master')
subprocess.check_call(['git', 'checkout', 'master'])
version = '%d.%d.%d%s' % (major, minor, revision, codename)
version_human = '%s %d.%d.%d' % (codename.strip('-'), major, minor, revision)
print('\033[1;32m[+] Building version '+version+'\033[0m')
print('\033[1;34m[*] Merge data...\033[0m')
os.chdir('data')
os.system('git merge dev --no-ff -m "Release '+version+': Merge branch \'dev\'"')
subprocess.check_call(['git', 'merge', 'dev', '--no-ff', '-m', 'Release '+version+': Merge branch \'dev\''])
print('\033[1;34m[*] Tag data...\033[0m')
os.system('git tag colobot-gold-'+version)
subprocess.check_call(['git', 'tag', 'colobot-gold-'+version])
print('\033[1;34m[*] Update dev on data...\033[0m')
os.system('git checkout dev')
os.system('git merge master --ff')
os.system('git checkout master')
subprocess.check_call(['git', 'checkout', 'dev'])
subprocess.check_call(['git', 'merge', 'master', '--ff'])
subprocess.check_call(['git', 'checkout', 'master'])
print('\033[1;34m[*] Merge main...\033[0m')
os.chdir('..')
os.system('git merge dev --no-ff -m "Release '+version+': Merge branch \'dev\'"')
subprocess.check_call(['git', 'merge', 'dev', '--no-ff', '-m', 'Release '+version+': Merge branch \'dev\''])
print('\033[1;34m[*] Bump version number\033[0m')
open('CMakeLists.txt', 'w').writelines(data)
os.system('git commit data CMakeLists.txt -m "Release '+version+': Bump version"')
subprocess.check_call(['git', 'commit', 'data', 'CMakeLists.txt', '-m', 'Release '+version+': Bump version'])
print('\033[1;34m[*] Tag main...\033[0m')
os.system('git tag colobot-gold-'+version)
subprocess.check_call(['git', 'tag', 'colobot-gold-'+version])
print('\033[1;34m[*] Update dev on main...\033[0m')
os.system('git checkout dev')
os.system('git merge master --ff')
subprocess.check_call(['git', 'checkout', 'dev'])
subprocess.check_call(['git', 'merge', 'master', '--ff'])
for i in range(len(data)):
m = re.match(r'^(#?)set\(COLOBOT_VERSION_(UNRELEASED|RELEASE_CODENAME)(.*)\)$', data[i])
if m:
comment = (m.group(2) == 'RELEASE_CODENAME')
data[i] = ('#' if comment else '')+'set(COLOBOT_VERSION_'+m.group(2)+m.group(3)+')\n'
open('CMakeLists.txt', 'w').writelines(data)
os.system('git commit CMakeLists.txt -m "Post-release '+version+'"')
os.system('git checkout master')
subprocess.check_call(['git', 'commit', 'CMakeLists.txt', '-m', 'Post-release '+version])
subprocess.check_call(['git', 'checkout', 'master'])
print('\033[1;32m[+] Done! Push when ready\033[0m')
print('\033[1;32m[+] Done preparing!\033[0m')
resp = ""
while resp != "yes":
resp = input("\033[1;35m[?] Ready to push? (type \'yes\'): \033[0m")
print('\033[1;34m[*] Pushing...\033[0m')
os.chdir('data')
subprocess.check_call(['git', 'push', 'origin', 'master', 'dev', 'colobot-gold-'+version])
os.chdir('..')
subprocess.check_call(['git', 'push', 'origin', 'master', 'dev', 'colobot-gold-'+version])
hub_available = True
try:
subprocess.check_call(['hub', '--version'])
except subprocess.CalledProcessError:
hub_available = False
print('\033[1;33m[!] hub is not available, will skip creating release drafts!\033[0m')
if hub_available:
print('\033[1;34m[*] Making release drafts on GitHub...\033[0m')
os.chdir('data')
release_notes = io.StringIO()
release_notes.write('Colobot: Gold Edition - '+version_human+' - data files\n')
release_notes.write('\n')
release_notes.write('Data files for release '+version)
subprocess.check_call(['hub', 'release', 'create', '--draft', '-m', release_notes.getvalue(), 'colobot-gold-'+version])
os.chdir('..')
release_notes = io.StringIO()
release_notes.write('Colobot: Gold Edition - '+version_human+'\n')
release_notes.write('\n')
release_notes.write('Release '+version+'\n')
release_notes.write('\n')
release_notes.write('[put release notes URL here]')
subprocess.check_call(['hub', 'release', 'create', '--draft', '-m', release_notes.getvalue(), 'colobot-gold-'+version])
print('\033[1;32m[+] Done!\033[0m')