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) set(COLOBOT_VERSION_REVISION 10)
# Used on official releases # Used on official releases
set(COLOBOT_VERSION_RELEASE_CODENAME "-alpha") #set(COLOBOT_VERSION_RELEASE_CODENAME "-alpha")
# Used on unreleased, development builds # Used on unreleased, development builds
#set(COLOBOT_VERSION_UNRELEASED "+alpha") set(COLOBOT_VERSION_UNRELEASED "+alpha")
# Append git characteristics to version # Append git characteristics to version
if(DEFINED COLOBOT_VERSION_UNRELEASED) 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" msgid "Origin of last message\\Shows where the last message was sent from"
msgstr "" msgstr ""
msgid "Speed 0.5x\\Half speed" msgid "Lower speed\\Decrease speed by half"
msgstr "" msgstr ""
msgid "Speed 1.0x\\Normal speed" msgid "Standard speed\\Reset speed to normal"
msgstr "" msgstr ""
msgid "Speed 1.5x\\1.5 times faster" msgid "Higher speed\\Doubles speed"
msgstr "" msgstr ""
msgid "Speed 2.0x\\Double speed" msgid "Quick save\\Immediately save game"
msgstr "" msgstr ""
msgid "Speed 3.0x\\Triple speed" msgid "Quick load\\Immediately load game"
msgstr ""
msgid "Speed 4.0x\\Quadruple speed"
msgstr ""
msgid "Speed 6.0x\\Sextuple speed"
msgstr "" msgstr ""
msgid "Pause\\Pause the game without opening menu" msgid "Pause\\Pause the game without opening menu"
@ -1533,6 +1527,9 @@ msgstr ""
msgid "Inappropriate bot" msgid "Inappropriate bot"
msgstr "" msgstr ""
msgid "Quicksave slot not found"
msgstr ""
msgid "Building completed" msgid "Building completed"
msgstr "" msgstr ""
@ -1773,6 +1770,24 @@ msgstr ""
msgid "This parameter needs a default value" msgid "This parameter needs a default value"
msgstr "" 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" msgid "Dividing by zero"
msgstr "" msgstr ""

134
po/de.po
View File

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

View File

@ -677,6 +677,13 @@ msgstr "Instructions sur la sélection"
msgid "Help balloons\\Explain the function of the buttons" msgid "Help balloons\\Explain the function of the buttons"
msgstr "Bulles d'aide\\Bulles explicatives" 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)" msgid "Highest\\Highest graphic quality (lowest frame rate)"
msgstr "Maxi\\Haute qualité (+ lent)" msgstr "Maxi\\Haute qualité (+ lent)"
@ -752,6 +759,9 @@ msgstr "Instructions mission\\Marche à suivre"
msgid "Internal error - tell the developers" msgid "Internal error - tell the developers"
msgstr "Erreur interne - contacter les développeurs" msgstr "Erreur interne - contacter les développeurs"
msgid "Invalid universal character name"
msgstr ""
msgid "Invert\\Invert values on this axis" msgid "Invert\\Invert values on this axis"
msgstr "Inversion\\Inverse les valeurs sur cet axe" msgstr "Inversion\\Inverse les valeurs sur cet axe"
@ -827,6 +837,23 @@ msgstr "Chargement des objets"
msgid "Loading terrain" msgid "Loading terrain"
msgstr "Chargement du 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)" msgid "Lowest\\Minimum graphic quality (highest frame rate)"
msgstr "Mini\\Qualité minimale (+ rapide)" msgstr "Mini\\Qualité minimale (+ rapide)"
@ -845,6 +872,12 @@ msgstr "Taille réduite"
msgid "Mipmap level\\Mipmap level" msgid "Mipmap level\\Mipmap level"
msgstr "Niveau de MIP mapping\\Niveau de MIP mapping" 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" msgid "Mission name"
msgstr "Nom de la mission" msgstr "Nom de la mission"
@ -1007,6 +1040,9 @@ msgstr "D'accord\\Compiler le programme"
msgid "Object too close" msgid "Object too close"
msgstr "Objet trop proche" msgstr "Objet trop proche"
msgid "Octal value out of range"
msgstr ""
msgid "One step" msgid "One step"
msgstr "Un pas" msgstr "Un pas"
@ -1181,6 +1217,16 @@ msgstr "Public\\Dossier commun à tous les joueurs"
msgid "Quake at explosions\\The screen shakes at explosions" msgid "Quake at explosions\\The screen shakes at explosions"
msgstr "Secousses lors d'explosions\\L'écran vibre lors d'une explosion" 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" msgid "Quit\\Quit Colobot: Gold Edition"
msgstr "Quitter\\Quitter Colobot : Édition Gold" msgstr "Quitter\\Quitter Colobot : Édition Gold"
@ -1391,27 +1437,6 @@ msgstr "Vaisseau spatial"
msgid "Spaceship ruin" msgid "Spaceship ruin"
msgstr "Epave de vaisseau spatial" 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" msgid "Spider"
msgstr "Araignée" msgstr "Araignée"
@ -1427,6 +1452,9 @@ msgstr "Action standard\\Action du bouton avec le cadre rouge"
msgid "Standard controls\\Standard key functions" msgid "Standard controls\\Standard key functions"
msgstr "Tout réinitialiser\\Remet toutes les touches standards" msgstr "Tout réinitialiser\\Remet toutes les touches standards"
msgid "Standard speed\\Reset speed to normal"
msgstr ""
msgid "Standard\\Standard appearance settings" msgid "Standard\\Standard appearance settings"
msgstr "Standard\\Remet les couleurs standards" msgstr "Standard\\Remet les couleurs standards"
@ -1616,6 +1644,9 @@ msgstr "Objet n'existe pas"
msgid "Unknown command" msgid "Unknown command"
msgstr "Commande inconnue" msgstr "Commande inconnue"
msgid "Unknown escape sequence"
msgstr ""
msgid "Unknown function" msgid "Unknown function"
msgstr "Routine inconnue" msgstr "Routine inconnue"
@ -1932,9 +1963,6 @@ msgstr "epsitec.com"
#~ msgid "Num of decorative objects\\Number of purely ornamental objects" #~ msgid "Num of decorative objects\\Number of purely ornamental objects"
#~ msgstr "Nb d'objets décoratifs\\Qualité d'objets non indispensables" #~ 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" #~ msgid "Planets and stars\\Astronomical objects in the sky"
#~ msgstr "Planètes et étoiles\\Motifs mobiles dans le ciel" #~ msgstr "Planètes et étoiles\\Motifs mobiles dans le ciel"
@ -1950,9 +1978,27 @@ msgstr "epsitec.com"
#~ msgid "Sky\\Clouds and nebulae" #~ msgid "Sky\\Clouds and nebulae"
#~ msgstr "Ciel\\Ciel et nuages" #~ 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" #~ msgid "Speed 3.0x\\Three times faster"
#~ msgstr "Vitesse 3.0x\\Trois fois plus rapide" #~ 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" #~ msgid "Sunbeams\\Sunbeams in the sky"
#~ msgstr "Rayons du soleil\\Rayons selon l'orientation" #~ 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" msgid "Help balloons\\Explain the function of the buttons"
msgstr "Dymki pomocy\\Wyjaśnia funkcje przycisków" 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)" msgid "Highest\\Highest graphic quality (lowest frame rate)"
msgstr "Najwyższa\\Maksymalna jakość grafiki (najniższa częstotliwość odświeżania)" 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" msgid "Internal error - tell the developers"
msgstr "Błąd wewnętrzny - powiadom twórców gry" msgstr "Błąd wewnętrzny - powiadom twórców gry"
msgid "Invalid universal character name"
msgstr ""
msgid "Invert\\Invert values on this axis" msgid "Invert\\Invert values on this axis"
msgstr "Odwróć\\Odwróć wartości na tej osi" msgstr "Odwróć\\Odwróć wartości na tej osi"
@ -828,6 +837,9 @@ msgstr "Wczytywanie obiektów"
msgid "Loading terrain" msgid "Loading terrain"
msgstr "Wczytywanie terenu" 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)" msgid "Lowest\\Minimum graphic quality (highest frame rate)"
msgstr "Najniższa\\Minimalna jakość grafiki (najwyższa częstotliwość odświeżania)" msgstr "Najniższa\\Minimalna jakość grafiki (najwyższa częstotliwość odświeżania)"
@ -846,6 +858,12 @@ msgstr "Pomniejsz"
msgid "Mipmap level\\Mipmap level" msgid "Mipmap level\\Mipmap level"
msgstr "Poziom mipmap\\Poziom mipmap" msgstr "Poziom mipmap\\Poziom mipmap"
msgid "Missing end quote"
msgstr ""
msgid "Missing hex digits after escape sequence"
msgstr ""
msgid "Mission name" msgid "Mission name"
msgstr "Nazwa misji" msgstr "Nazwa misji"
@ -1008,6 +1026,9 @@ msgstr "OK\\Zamyka edytor programu i powraca do gry"
msgid "Object too close" msgid "Object too close"
msgstr "Obiekt za blisko" msgstr "Obiekt za blisko"
msgid "Octal value out of range"
msgstr ""
msgid "One step" msgid "One step"
msgstr "Jeden krok" msgstr "Jeden krok"
@ -1182,6 +1203,15 @@ msgstr "Publiczny\\Folder ogólnodostępny"
msgid "Quake at explosions\\The screen shakes at explosions" msgid "Quake at explosions\\The screen shakes at explosions"
msgstr "Wstrząsy przy wybuchach\\Ekran trzęsie się podczas wybuchów" 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" msgid "Quit\\Quit Colobot: Gold Edition"
msgstr "Wyjdź\\Kończy grę Colobot: Gold Edition" msgstr "Wyjdź\\Kończy grę Colobot: Gold Edition"
@ -1392,27 +1422,6 @@ msgstr "Statek kosmiczny"
msgid "Spaceship ruin" msgid "Spaceship ruin"
msgstr "Ruiny statku kosmicznego" 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" msgid "Spider"
msgstr "Pająk" msgstr "Pająk"
@ -1428,6 +1437,9 @@ msgstr "Standardowa akcja\\Standardowa akcja robota (podnieś/upuść, strzelaj,
msgid "Standard controls\\Standard key functions" msgid "Standard controls\\Standard key functions"
msgstr "Standardowa kontrola\\Standardowe klawisze funkcyjne" 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" msgid "Standard\\Standard appearance settings"
msgstr "Standardowe\\Standardowe ustawienia wyglądu" msgstr "Standardowe\\Standardowe ustawienia wyglądu"
@ -1617,6 +1629,9 @@ msgstr "Obiekt nieznany"
msgid "Unknown command" msgid "Unknown command"
msgstr "Nieznane polecenie" msgstr "Nieznane polecenie"
msgid "Unknown escape sequence"
msgstr ""
msgid "Unknown function" msgid "Unknown function"
msgstr "Funkcja nieznana" msgstr "Funkcja nieznana"

View File

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

View File

@ -241,6 +241,12 @@ enum CBotError : int
CBotErrNoClassName = 5046, //!< class name expected CBotErrNoClassName = 5046, //!< class name expected
CBotErrNoReturn = 5047, //!< non-void function needs "return;" CBotErrNoReturn = 5047, //!< non-void function needs "return;"
CBotErrDefaultValue = 5048, //!< this parameter needs a default value 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 // Runtime errors
CBotErrZeroDiv = 6000, //!< division by zero CBotErrZeroDiv = 6000, //!< division by zero

View File

@ -42,15 +42,136 @@ CBotInstr* CBotExprLitString::Compile(CBotToken* &p, CBotCStack* pStack)
{ {
CBotCStack* pStk = pStack->TokenStack(); CBotCStack* pStk = pStack->TokenStack();
CBotExprLitString* inst = new CBotExprLitString(); std::string s = p->GetString();
inst->SetToken(p); auto it = s.cbegin();
p = p->GetNext(); 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;
}
CBotVar* var = CBotVar::Create("", CBotTypString); if (++it == s.cend()) break;
pStk->SetVar(var);
return pStack->Return(inst, pStk); 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();
CBotVar* var = CBotVar::Create("", CBotTypString);
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); CBotVar* var = CBotVar::Create("", CBotTypString);
std::string chaine = m_token.GetString(); var->SetValString(m_valstring);
chaine = chaine.substr(1, chaine.length()-2); // removes the quotes
var->SetValString(chaine); // value of the number
pile->SetVar(var); // put on the stack pile->SetVar(var); // put on the stack

View File

@ -58,6 +58,9 @@ public:
protected: protected:
virtual const std::string GetDebugName() override { return "CBotExprLitString"; } virtual const std::string GetDebugName() override { return "CBotExprLitString"; }
virtual std::string GetDebugData() override; virtual std::string GetDebugData() override;
private:
std::string m_valstring = "";
}; };
} // namespace CBot } // 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 // This is an element of the current class
// ads the equivalent of this. before // ads the equivalent of this. before
CBotToken token("this"); CBotToken token("this");
// invisible 'this.' highlights member token on error
token.SetPos(p->GetStart(), p->GetEnd());
inst->SetToken(&token); inst->SetToken(&token);
(static_cast<CBotExprVar*>(inst))->m_nIdent = -2; // identificator for this (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 // this is an element of the current class
// adds the equivalent of this. before // adds the equivalent of this. before
// invisible 'this.' highlights member token on error
pthis.SetPos(pp->GetStart(), pp->GetEnd());
inst->SetToken(&pthis); inst->SetToken(&pthis);
(static_cast<CBotExprVar*>(inst))->m_nIdent = -2; // ident for this (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"); CBotVar* pThis = pile->FindVar("this");
pThis->SetInit(CBotVar::InitType::IS_POINTER); pThis->SetInit(CBotVar::InitType::IS_POINTER);
pThis->SetPointer(pInstance);
pThis->SetUniqNum(-2); pThis->SetUniqNum(-2);
} }
@ -672,6 +673,7 @@ int CBotFunction::DoCall(CBotProgram* program, const std::list<CBotFunction*>& l
{ {
CBotTypResult type; CBotTypResult type;
CBotFunction* pt = nullptr; CBotFunction* pt = nullptr;
CBotProgram* baseProg = pStack->GetProgram(true);
pt = FindLocalOrPublic(localFunctionList, nIdent, name, ppVars, type); 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()) if (pStk3b->GetState() == 0 && !pt->m_MasterClass.empty())
{ {
CBotVar* pInstance = program->m_thisVar; CBotVar* pInstance = (baseProg != nullptr) ? baseProg->m_thisVar : nullptr;
// make "this" known // make "this" known
CBotVar* pThis ; CBotVar* pThis ;
if ( pInstance == nullptr ) if ( pInstance == nullptr )
@ -762,8 +764,7 @@ void CBotFunction::RestoreCall(const std::list<CBotFunction*>& localFunctionList
CBotFunction* pt = nullptr; CBotFunction* pt = nullptr;
CBotStack* pStk1; CBotStack* pStk1;
CBotStack* pStk3; CBotStack* pStk3;
CBotProgram* baseProg = pStack->GetProgram(true);
// search function to return the ok identifier
pt = FindLocalOrPublic(localFunctionList, nIdent, name, ppVars, type); pt = FindLocalOrPublic(localFunctionList, nIdent, name, ppVars, type);
@ -792,10 +793,11 @@ void CBotFunction::RestoreCall(const std::list<CBotFunction*>& localFunctionList
{ {
if ( !pt->m_MasterClass.empty() ) if ( !pt->m_MasterClass.empty() )
{ {
// CBotVar* pInstance = m_pProg->m_thisVar; CBotVar* pInstance = (baseProg != nullptr) ? baseProg->m_thisVar : nullptr;
// make "this" known // make "this" known
CBotVar* pThis = pStk1->FindVar("this"); CBotVar* pThis = pStk1->FindVar("this");
pThis->SetInit(CBotVar::InitType::IS_POINTER); pThis->SetInit(CBotVar::InitType::IS_POINTER);
pThis->SetPointer(pInstance);
pThis->SetUniqNum(-2); pThis->SetUniqNum(-2);
} }
} }

View File

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

View File

@ -405,9 +405,20 @@ bool CBotTwoOpExpr::Execute(CBotStack* &pStack)
// creates a variable for the result // creates a variable for the result
CBotVar* result = CBotVar::Create("", TypeRes); 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 // creates a variable to perform the calculation in the appropriate type
if ( TypeRes != CBotTypString ) // keep string conversion if ( TypeRes != CBotTypString ) // keep string conversion
{
TypeRes = std::max(type1.GetType(), type2.GetType()); TypeRes = std::max(type1.GetType(), type2.GetType());
}
else
{
left->Update(nullptr);
right->Update(nullptr);
}
if ( GetTokenType() == ID_ADD && type1.Eq(CBotTypString) ) if ( GetTokenType() == ID_ADD && type1.Eq(CBotTypString) )
{ {
@ -422,8 +433,6 @@ bool CBotTwoOpExpr::Execute(CBotStack* &pStack)
CBotError err = CBotNoErr; CBotError err = CBotNoErr;
// is a operation according to request // is a operation according to request
CBotVar* left = pStk1->GetVar();
CBotVar* right = pStk2->GetVar();
switch (GetTokenType()) 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) static char sep1[] = " \r\n\t,:()[]{}-+*/=;><!~^|&%.\"\'?";
{
if (c == list[i++]) return true;
if (list[i] == 0) return false;
}
}
static char sep1[] = " \r\n\t,:()[]{}-+*/=;><!~^|&%.";
static char sep2[] = " \r\n\t"; // only separators 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 num[] = "0123456789"; // point (single) is tested separately
static char hexnum[] = "0123456789ABCDEFabcdef"; 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) CBotToken* CBotToken::NextToken(const char*& program, bool first)
@ -278,14 +268,13 @@ CBotToken* CBotToken::NextToken(const char*& program, bool first)
// special case for strings // special case for strings
if (token[0] == '\"' ) if (token[0] == '\"' )
{ {
while (c != 0 && !CharInList(c, nch)) while (c != 0 && c != '\"' && !CharInList(c, nch))
{ {
if ( c == '\\' ) if ( c == '\\' )
{ {
c = *(program++); // next character token += c;
if ( c == 'n' ) c = '\n'; c = *(program++);
if ( c == 'r' ) c = '\r'; if (c == 0 || CharInList(c, nch)) break;
if ( c == 't' ) c = '\t';
} }
token += c; token += c;
c = *(program++); c = *(program++);

View File

@ -236,4 +236,49 @@ float GetNumFloat(const std::string& str)
return static_cast<float>(num); 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 } // namespace CBot

View File

@ -96,6 +96,21 @@ long GetNumInt(const std::string& str);
*/ */
float GetNumFloat(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 template<typename T> class CBotLinkedList
{ {
public: public:

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -22,10 +22,6 @@
#include <stdio.h> #include <stdio.h>
template<> CLogger* CSingleton<CLogger>::m_instance = nullptr;
CLogger::CLogger() CLogger::CLogger()
{ {
#if DEV_BUILD #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_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_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_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_SPEED_DEC] = TR("Lower speed\\Decrease speed by half");
stringsEvent[EVENT_INTERFACE_KEY+INPUT_SLOT_SPEED10] = TR("Speed 1.0x\\Normal speed"); stringsEvent[EVENT_INTERFACE_KEY+INPUT_SLOT_SPEED_RESET] = TR("Standard speed\\Reset speed to normal");
stringsEvent[EVENT_INTERFACE_KEY+INPUT_SLOT_SPEED15] = TR("Speed 1.5x\\1.5 times faster"); stringsEvent[EVENT_INTERFACE_KEY+INPUT_SLOT_SPEED_INC] = TR("Higher speed\\Doubles speed");
stringsEvent[EVENT_INTERFACE_KEY+INPUT_SLOT_SPEED20] = TR("Speed 2.0x\\Double speed"); stringsEvent[EVENT_INTERFACE_KEY+INPUT_SLOT_QUICKSAVE] = TR("Quick save\\Immediately save game");
stringsEvent[EVENT_INTERFACE_KEY+INPUT_SLOT_SPEED30] = TR("Speed 3.0x\\Triple speed"); stringsEvent[EVENT_INTERFACE_KEY+INPUT_SLOT_QUICKLOAD] = TR("Quick load\\Immediately load game");
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_PAUSE] = TR("Pause\\Pause the game without opening menu"); 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"); 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_DELETEBUILDING] = TR("Building destroyed");
stringsErr[ERR_ENEMY_OBJECT] = TR("Unable to control enemy objects"); stringsErr[ERR_ENEMY_OBJECT] = TR("Unable to control enemy objects");
stringsErr[ERR_WRONG_BOT] = TR("Inappropriate bot"); 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_BUILD] = TR("Building completed");
stringsErr[INFO_CONVERT] = TR("Titanium available"); stringsErr[INFO_CONVERT] = TR("Titanium available");
@ -732,6 +731,12 @@ void InitializeRestext()
stringsCbot[CBot::CBotErrNoClassName] = TR("Class name expected"); stringsCbot[CBot::CBotErrNoClassName] = TR("Class name expected");
stringsCbot[CBot::CBotErrNoReturn] = TR("Non-void function needs \"return;\""); stringsCbot[CBot::CBotErrNoReturn] = TR("Non-void function needs \"return;\"");
stringsCbot[CBot::CBotErrDefaultValue] = TR("This parameter needs a default value"); 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::CBotErrZeroDiv] = TR("Dividing by zero");
stringsCbot[CBot::CBotErrNotInit] = TR("Variable not initialized"); stringsCbot[CBot::CBotErrNotInit] = TR("Variable not initialized");

View File

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

View File

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

View File

@ -73,3 +73,4 @@ private:
CSingleton(const CSingleton<T> &) = delete; 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_surface.h>
#include <SDL_thread.h> #include <SDL_thread.h>
template<> Gfx::CEngine* CSingleton<Gfx::CEngine>::m_instance = nullptr;
// Graphics module namespace // Graphics module namespace
namespace Gfx namespace Gfx
{ {
@ -2633,6 +2631,10 @@ void CEngine::SetFocus(float focus)
float farPlane = m_deepView[0] * m_clippingDistance; float farPlane = m_deepView[0] * m_clippingDistance;
float aspect = static_cast<float>(m_size.x) / static_cast<float>(m_size.y); 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); Math::LoadProjectionMatrix(m_matProj, m_focus, aspect, 0.5f, farPlane);
} }
@ -2641,6 +2643,16 @@ float CEngine::GetFocus()
return m_focus; return m_focus;
} }
float CEngine::GetVFovAngle()
{
return m_focus;
}
float CEngine::GetHFovAngle()
{
return m_hfov;
}
void CEngine::SetShadowColor(float value) void CEngine::SetShadowColor(float value)
{ {
m_shadowColor = value; m_shadowColor = value;
@ -3740,6 +3752,7 @@ void CEngine::RenderShadowMap()
m_shadowMapping = false; m_shadowMapping = false;
m_offscreenShadowRendering = false; m_offscreenShadowRendering = false;
m_qualityShadows = false; m_qualityShadows = false;
CProfiler::StopPerformanceCounter(PCNT_RENDER_SHADOW_MAP);
return; 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;
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; // Note the background covers Math::PI radians, i.e. it repeats twice per rotation!
u2 = u1+1.0f/Math::PI; 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; v1 = (1.0f-h)*(0.5f+a/(2.0f*Math::PI/4.0f))+0.1f;
v2 = v1+h; v2 = v1+h;

View File

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

View File

@ -115,8 +115,16 @@ void CPlanet::Draw()
Math::Point p1, p2; Math::Point p1, p2;
float a = eyeDirH + planet.angle.x; // Determine the 2D coordinates of the centre of the planet.
p1.x = Math::Mod(a, Math::PI*2.0f)-0.5f;
// 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; a = eyeDirV + planet.angle.y;
p1.y = 0.4f+(Math::Mod(a+Math::PI, Math::PI*2.0f)-Math::PI)*(2.0f/Math::PI); 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"); CLevelParserLine* line = levelParser.Get("Mission");
cat = GetLevelCategoryFromDir(line->GetParam("base")->AsString()); cat = GetLevelCategoryFromDir(line->GetParam("base")->AsString());
if (dir == "../../crashsave") LoadFinishedLevels(cat);
rank = line->GetParam("rank")->AsInt(); rank = line->GetParam("rank")->AsInt();
if (cat == LevelCategory::CustomLevels) 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_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 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 //! Constructor of robot application
CRobotMain::CRobotMain() CRobotMain::CRobotMain()
{ {
@ -971,33 +968,25 @@ bool CRobotMain::ProcessEvent(Event &event)
{ {
StartDisplayVisit(EVENT_NULL); 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); 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); QuickLoad();
}
if (data->slot == INPUT_SLOT_SPEED40)
{
SetSpeed(4.0f);
}
if (data->slot == INPUT_SLOT_SPEED60)
{
SetSpeed(6.0f);
} }
if (data->key == KEY(c) && ((event.kmodState & KEY_MOD(CTRL)) != 0) && m_engine->GetShowStats()) 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 //! Advances the entire scene
bool CRobotMain::EventFrame(const Event &event) 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; 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_water->EventProcess(event);
m_cloud->EventProcess(event); m_cloud->EventProcess(event);
@ -2422,6 +2381,40 @@ bool CRobotMain::EventFrame(const Event &event)
if (toto != nullptr) if (toto != nullptr)
dynamic_cast<CInteractiveObject*>(toto)->EventProcess(event); 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); HiliteFrame(event.rTime);
// Moves the film indicator. // 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())); 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); m_ui->GetLoadingScreen()->SetProgress(1.0f, RT_LOADING_FINISHED);
if (m_ui->GetLoadingScreen()->IsVisible()) if (m_ui->GetLoadingScreen()->IsVisible())
{ {
// Force render of the "Loading finished" screen // Force render of the "Loading finished" screen because it looks weird when the progress bar disappears in the middle
// 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"
m_app->Render(); m_app->Render();
} }
@ -3695,7 +3689,7 @@ void CRobotMain::CreateScene(bool soluce, bool fixScene, bool resetObject)
// TODO: m_engine->TimeInit(); ?? // TODO: m_engine->TimeInit(); ??
m_input->ResetKeyStates(); m_input->ResetKeyStates();
m_time = 0.0f; m_time = 0.0f;
m_gameTime = 0.0f; if (m_sceneReadPath.empty()) m_gameTime = 0.0f;
m_gameTimeAbsolute = 0.0f; m_gameTimeAbsolute = 0.0f;
m_autosaveLast = 0.0f; m_autosaveLast = 0.0f;
m_infoUsed = 0; m_infoUsed = 0;
@ -4548,6 +4542,7 @@ bool CRobotMain::IOWriteScene(std::string filename, std::string filecbot, std::s
else else
line->AddParam("chap", MakeUnique<CLevelParserParam>(m_levelChap)); line->AddParam("chap", MakeUnique<CLevelParserParam>(m_levelChap));
line->AddParam("rank", MakeUnique<CLevelParserParam>(m_levelRank)); line->AddParam("rank", MakeUnique<CLevelParserParam>(m_levelRank));
line->AddParam("gametime", MakeUnique<CLevelParserParam>(GetGameTime()));
levelParser.AddLine(std::move(line)); levelParser.AddLine(std::move(line));
line = MakeUnique<CLevelParserLine>("Map"); line = MakeUnique<CLevelParserLine>("Map");
@ -4728,6 +4723,9 @@ CObject* CRobotMain::IOReadScene(std::string filename, std::string filecbot)
int objCounter = 0; int objCounter = 0;
for (auto& line : levelParser.GetLines()) for (auto& line : levelParser.GetLines())
{ {
if (line->GetCommand() == "Mission")
m_gameTime = line->GetParam("gametime")->AsFloat(0.0f);
if (line->GetCommand() == "Map") if (line->GetCommand() == "Map")
m_map->ZoomMap(line->GetParam("zoom")->AsFloat()); m_map->ZoomMap(line->GetParam("zoom")->AsFloat());
@ -5563,6 +5561,31 @@ void CRobotMain::Autosave()
m_playerProfile->SaveScene(dir, info); 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) void CRobotMain::SetExitAfterMission(bool exit)
{ {
m_exitAfterMission = exit; m_exitAfterMission = exit;
@ -5824,6 +5847,7 @@ void CRobotMain::CreateCodeBattleInterface()
pw->CreateButton(pos, ddim, 13, EVENT_CODE_BATTLE_SPECTATOR); pw->CreateButton(pos, ddim, 13, EVENT_CODE_BATTLE_SPECTATOR);
} }
if (!m_scoreboard) return;
pos.y += ddim.y; pos.y += ddim.y;
ddim.y = textHeight; ddim.y = textHeight;
int i = 0; int i = 0;

View File

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

View File

@ -405,12 +405,12 @@ bool CAutoFactory::EventProcess(const Event &event)
{ {
Program* program = dynamic_cast<CProgramStorageObject*>(vehicle)->AddProgram(); 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"; 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()); 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()); 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) //! 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. */ /** 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; 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); float energy = GetObjectEnergyLevel(m_object);
if (energy == 0.0f) return true; 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; factor = 0.5f+energy*0.5f;
if ( bOnBoard ) factor *= 0.8f; if ( bOnBoard ) factor *= 0.8f;

View File

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

View File

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

View File

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

View File

@ -803,7 +803,8 @@ Error CTaskGoto::Start(Math::Vector goal, float altitude,
Error CTaskGoto::IsEnded() Error CTaskGoto::IsEnded()
{ {
Math::Vector pos; 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_engine->GetPause() ) return ERR_CONTINUE;
if ( m_error != ERR_OK ) return m_error; if ( m_error != ERR_OK ) return m_error;
@ -916,7 +917,9 @@ Error CTaskGoto::IsEnded()
if ( m_goalMode == TGG_EXPRESS ) if ( m_goalMode == TGG_EXPRESS )
{ {
dist = Math::DistanceProjected(m_goal, pos); 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; return ERR_STOP;
} }

View File

@ -376,5 +376,5 @@ bool CTaskRecover::Abort()
CObject* CTaskRecover::SearchRuin() 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,12 +363,109 @@ bool CTaskTerraform::Terraform()
type = pObj->GetType(); type = pObj->GetType();
if ( type == OBJECT_NULL ) continue; 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()); dist = Math::Distance(m_terraPos, pObj->GetPosition());
if ( dist > 20.0f ) continue;
m_engine->GetPyroManager()->Create(Gfx::PT_FRAGT, pObj); 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 else
{ {
@ -388,6 +485,14 @@ bool CTaskTerraform::Terraform()
if (type == OBJECT_SPIDER) actionType = MSS_BACK1; if (type == OBJECT_SPIDER) actionType = MSS_BACK1;
motion->SetAction(actionType, 0.8f+Math::Rand()*0.3f); motion->SetAction(actionType, 0.8f+Math::Rand()*0.3f);
dynamic_cast<CBaseAlien*>(pObj)->SetFixed(true); // not moving 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 ( m_bLeft )
{ {
if ( angle <= m_startAngle+m_angle ) if ( angle <= m_finalAngle )
{ {
m_physics->SetMotorSpeedZ(0.0f); m_physics->SetMotorSpeedZ(0.0f);
//? m_physics->SetCirMotionY(MO_MOTSPEED, 0.0f); //? m_physics->SetCirMotionY(MO_MOTSPEED, 0.0f);
@ -118,10 +118,15 @@ Error CTaskTurn::IsEnded()
m_object->SetRotationY(m_finalAngle); m_object->SetRotationY(m_finalAngle);
return ERR_STOP; return ERR_STOP;
} }
if ( !m_bDecel && angle <= m_startAngle+m_angle)
{
m_bDecel = true;
m_physics->SetMotorSpeedZ(-0.5f);
}
} }
else else
{ {
if ( angle >= m_startAngle+m_angle ) if ( angle >= m_finalAngle )
{ {
m_physics->SetMotorSpeedZ(0.0f); m_physics->SetMotorSpeedZ(0.0f);
//? m_physics->SetCirMotionY(MO_MOTSPEED, 0.0f); //? m_physics->SetCirMotionY(MO_MOTSPEED, 0.0f);
@ -130,6 +135,11 @@ Error CTaskTurn::IsEnded()
m_object->SetRotationY(m_finalAngle); m_object->SetRotationY(m_finalAngle);
return ERR_STOP; return ERR_STOP;
} }
if ( !m_bDecel && angle >= m_startAngle+m_angle)
{
m_bDecel = true;
m_physics->SetMotorSpeedZ(0.5f);
}
} }
return ERR_CONTINUE; return ERR_CONTINUE;

View File

@ -41,4 +41,5 @@ protected:
float m_finalAngle = 0.0f; float m_finalAngle = 0.0f;
bool m_bLeft = false; bool m_bLeft = false;
bool m_bError = 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, "factory" ) == 0 ) helpfile = "cbot/factory";
if ( strcmp(token, "destroy" ) == 0 ) helpfile = "cbot/destroy"; if ( strcmp(token, "destroy" ) == 0 ) helpfile = "cbot/destroy";
if ( strcmp(token, "search" ) == 0 ) helpfile = "cbot/search"; 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, "radar" ) == 0 ) helpfile = "cbot/radar";
if ( strcmp(token, "radarall" ) == 0 ) helpfile = "cbot/radarall"; if ( strcmp(token, "radarall" ) == 0 ) helpfile = "cbot/radarall";
if ( strcmp(token, "direction" ) == 0 ) helpfile = "cbot/direct"; 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, "takeoff" ) == 0 ) return true;
if ( strcmp(token, "destroy" ) == 0 ) return true; if ( strcmp(token, "destroy" ) == 0 ) return true;
if ( strcmp(token, "search" ) == 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, "radar" ) == 0 ) return true;
if ( strcmp(token, "radarall" ) == 0 ) return true; if ( strcmp(token, "radarall" ) == 0 ) return true;
if ( strcmp(token, "detect" ) == 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, "research" ) == 0 ) return "object.research ( type );";
if ( strcmp(token, "takeoff" ) == 0 ) return "object.takeoff ( );"; if ( strcmp(token, "takeoff" ) == 0 ) return "object.takeoff ( );";
if ( strcmp(token, "destroy" ) == 0 ) return "object.destroy ( );"; 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, "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, "radarall" ) == 0 ) return "radarall ( cat, angle, focus, min, max, sens, filter );";
if ( strcmp(token, "detect" ) == 0 ) return "detect ( cat );"; 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); 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. // 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; 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; color = Gfx::FONT_HIGHLIGHT_STRING;
} }
else if (type == CBot::TokenTypString) // string literals
{
HighlightString(edit, token, cursor1);
bt = bt->GetNext();
continue;
}
assert(cursor1 < cursor2); assert(cursor1 < cursor2);
edit->SetFormat(cursor1, cursor2, color); edit->SetFormat(cursor1, cursor2, color);

View File

@ -79,9 +79,9 @@ CBotTypResult CScriptFunctions::cClassOneFloat(CBotVar* thisclass, CBotVar* &var
return cOneFloat(var, nullptr); 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); if ( var == nullptr ) return CBotTypResult(CBotErrLowParam);
@ -695,66 +695,113 @@ bool CScriptFunctions::rDelete(CBotVar* var, CBotVar* result, int& exception, vo
CObjectManager::GetInstancePointer()->DeleteObject(obj); 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;
} }
CBotTypResult compileSearch(CBotVar* &var, void* user, CBotTypResult returnValue)
// Compilation of the instruction "search(type, pos)".
CBotTypResult CScriptFunctions::cSearch(CBotVar* &var, void* user)
{ {
CBotVar* array;
CBotTypResult ret;
if ( var == nullptr ) return CBotTypResult(CBotErrLowParam); if ( var == nullptr ) return CBotTypResult(CBotErrLowParam);
if ( var->GetType() == CBotTypArrayPointer ) if ( var->GetType() == CBotTypArrayPointer )
{ {
array = var->GetItemList(); CBotTypResult type = var->GetTypResult().GetTypElem();
if ( array == nullptr ) return CBotTypResult(CBotTypPointer); if ( type.GetType() > CBotTypDouble ) return CBotTypResult(CBotErrBadParam); // type
if ( array->GetType() > CBotTypDouble ) return CBotTypResult(CBotErrBadNum);
} }
else if ( var->GetType() > CBotTypDouble ) return CBotTypResult(CBotErrBadNum); else if ( var->GetType() > CBotTypDouble ) return CBotTypResult(CBotErrBadNum); // type
var = var->GetNext(); 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; return compileSearch(var, user, CBotTypResult(CBotTypPointer, "object"));
CObject *pBest; }
CBotVar* array;
Math::Vector pos, oPos; CBotTypResult CScriptFunctions::cSearchAll(CBotVar* &var, void* user)
bool bArray; {
int type; 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->GetType() == CBotTypArrayPointer )
{
array = var->GetItemList();
bArray = true;
}
else
{
type = var->GetValInt();
bArray = false;
}
var = var->GetNext();
if ( var != nullptr ) if ( var != nullptr )
{ {
if ( !GetPoint(var, exception, pos) ) return true; if ( var->GetType() == CBotTypArrayPointer )
} {
else array = var->GetItemList();
{ bArray = true;
pos = pThis->GetPosition(); }
else
{
type = var->GetValInt();
bArray = false;
}
var = var->GetNext();
if ( var != nullptr )
{
if ( !GetPoint(var, exception, pos) ) return false;
if ( var != nullptr )
{
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; std::vector<ObjectType> type_v;
@ -774,18 +821,47 @@ 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);
}
if ( pBest == nullptr ) bool CScriptFunctions::rSearch(CBotVar* var, CBotVar* result, int& exception, void* user)
{ {
result->SetPointer(nullptr); CObject* pThis = static_cast<CScript*>(user)->m_object;
}
else
{
result->SetPointer(pBest->GetBotVar());
}
return true; 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 )
{
result->SetPointer(nullptr);
}
else
{
result->SetPointer(pBest->GetBotVar());
}
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; CBotTypResult ret;
if ( var == nullptr ) return CBotTypResult(CBotErrLowParam); if ( var == nullptr ) return CBotTypResult(CBotErrLowParam);
ret = CScriptFunctions::cPoint(var, user); ret = cPoint(var, user);
if ( ret.GetType() != 0 ) return ret; if ( ret.GetType() != 0 ) return ret;
if ( var == nullptr ) return CBotTypResult(CBotTypFloat); if ( var == nullptr ) return CBotTypResult(CBotTypFloat);
@ -3249,6 +3325,7 @@ void CScriptFunctions::Init()
CBotProgram::AddFunction("retobjectbyid", rGetObjectById, cGetObject); CBotProgram::AddFunction("retobjectbyid", rGetObjectById, cGetObject);
CBotProgram::AddFunction("delete", rDelete, cDelete); CBotProgram::AddFunction("delete", rDelete, cDelete);
CBotProgram::AddFunction("search", rSearch, cSearch); CBotProgram::AddFunction("search", rSearch, cSearch);
CBotProgram::AddFunction("searchall", rSearchAll, cSearchAll);
CBotProgram::AddFunction("radar", rRadar, cRadar); CBotProgram::AddFunction("radar", rRadar, cRadar);
CBotProgram::AddFunction("radarall", rRadarAll, cRadarAll); CBotProgram::AddFunction("radarall", rRadarAll, cRadarAll);
CBotProgram::AddFunction("detect", rDetect, cDetect); CBotProgram::AddFunction("detect", rDetect, cDetect);

View File

@ -57,6 +57,7 @@ private:
static CBot::CBotTypResult cGetObject(CBot::CBotVar* &var, void* user); static CBot::CBotTypResult cGetObject(CBot::CBotVar* &var, void* user);
static CBot::CBotTypResult cDelete(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 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 cRadar(CBot::CBotVar* &var, void* user);
static CBot::CBotTypResult cRadarAll(CBot::CBotVar* &var, void* user); static CBot::CBotTypResult cRadarAll(CBot::CBotVar* &var, void* user);
static CBot::CBotTypResult cDetect(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 cPenDown(CBot::CBotVar* &var, void* user);
static CBot::CBotTypResult cOnePoint(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 CBot::CBotTypResult cOneObject(CBot::CBotVar* &var, void* user);
static bool rEndMission(CBot::CBotVar* var, CBot::CBotVar* result, int& exception, 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 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 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 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 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 rRadarAll(CBot::CBotVar* var, CBot::CBotVar* result, int& exception, void* user);
static bool rDetect(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_FRAME = (1<<13), // framework highlighting
STATE_WARNING = (1<<14), // framework hatched yellow / black STATE_WARNING = (1<<14), // framework hatched yellow / black
STATE_VALUE = (1<<15), // displays the value 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 namespace Ui
{ {
const float MARGX = (5.0f/640.0f); const float MARGX = (3.75f/640.0f);
const float MARGY = (5.0f/480.0f); const float MARGY = (3.75f/480.0f);
const float MARGYS = (4.0f/480.0f); const float MARGYS = (2.75f/480.0f);
const float MARGY1 = (1.0f/480.0f); const float MARGY1 = (1.0f/480.0f);
//! time limit for double-click //! time limit for double-click
const float DELAY_DBCLICK = 0.75f; const float DELAY_DBCLICK = 0.75f;

View File

@ -209,6 +209,27 @@ void CShortcut::Draw()
DrawIcon(m_pos, m_dim, uv1, uv2); 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);
}
} }
// Draw the vertex array. // Draw the vertex array.

View File

@ -247,6 +247,7 @@ bool CMainShort::UpdateShortcuts()
assert(m_shortcuts[i]->Implements(ObjectInterfaceType::Controllable)); assert(m_shortcuts[i]->Implements(ObjectInterfaceType::Controllable));
pc->SetState(STATE_CHECK, dynamic_cast<CControllableObject*>(m_shortcuts[i])->GetSelect()); 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_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; return true;

View File

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

View File

@ -108,6 +108,10 @@ protected:
Math::Point m_editActualDim; Math::Point m_editActualDim;
Math::Point m_editFinalPos; Math::Point m_editFinalPos;
Math::Point m_editFinalDim; 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_time;
float m_fixInfoTextTime; float m_fixInfoTextTime;

View File

@ -1533,6 +1533,120 @@ TEST_F(CBotUT, String)
" ASSERT(c == \"Colobot!\");\n" " ASSERT(c == \"Colobot!\");\n"
"}\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 // 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 # Script to use when releasing new versions
# Run from main repo directory with data submodule pulled in data/ # 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: # 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 # * Make sure you don't forget to pull any changes before you start
# * Get current version number from CMakeLists.txt # * Get current version number from CMakeLists.txt
# * Merge dev -> master in the data submodule # * Merge dev -> master in the data submodule
@ -13,26 +14,48 @@
# * Bump version number in main repo # * Bump version number in main repo
# * Tag release in main repo # * Tag release in main repo
# * Update dev in main repo to point to the new merge commit # * 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 # After finished, verify everything is correct and push the changes
import os import os
import re 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') print('\033[1;34m[*] Make sure all remote changes are pulled...\033[0m')
os.system('git checkout dev') subprocess.check_call(['git', 'checkout', 'dev'])
os.system('git pull --ff') subprocess.check_call(['git', 'pull', '--ff'])
os.system('git checkout master') subprocess.check_call(['git', 'checkout', 'master'])
os.system('git pull --ff') subprocess.check_call(['git', 'pull', '--ff'])
os.chdir('data') os.chdir('data')
os.system('git checkout dev') subprocess.check_call(['git', 'checkout', 'dev'])
os.system('git pull --ff') subprocess.check_call(['git', 'pull', '--ff'])
os.system('git checkout master') subprocess.check_call(['git', 'checkout', 'master'])
os.system('git pull --ff') subprocess.check_call(['git', 'pull', '--ff'])
os.chdir('..') os.chdir('..')
print('\033[1;34m[*] Get version numbers...\033[0m') print('\033[1;34m[*] Get version numbers...\033[0m')
os.system('git checkout dev') subprocess.check_call(['git', 'checkout', 'dev'])
major = None major = None
minor = None minor = None
revision = None revision = None
@ -40,7 +63,7 @@ codename = None
data = open('CMakeLists.txt', 'r').readlines() data = open('CMakeLists.txt', 'r').readlines()
for i in range(len(data)): 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: if m:
x = int(m.group(3)) x = int(m.group(3))
if m.group(1) == 'MAJOR': if m.group(1) == 'MAJOR':
@ -60,43 +83,79 @@ for i in range(len(data)):
codename = m.group(4) codename = m.group(4)
data[i] = ('#' if comment else '')+'set(COLOBOT_VERSION_'+m.group(2)+m.group(3)+'"'+m.group(4)+'")\n' 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 = '%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;32m[+] Building version '+version+'\033[0m')
print('\033[1;34m[*] Merge data...\033[0m') print('\033[1;34m[*] Merge data...\033[0m')
os.chdir('data') 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') 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') print('\033[1;34m[*] Update dev on data...\033[0m')
os.system('git checkout dev') subprocess.check_call(['git', 'checkout', 'dev'])
os.system('git merge master --ff') subprocess.check_call(['git', 'merge', 'master', '--ff'])
os.system('git checkout master') subprocess.check_call(['git', 'checkout', 'master'])
print('\033[1;34m[*] Merge main...\033[0m') print('\033[1;34m[*] Merge main...\033[0m')
os.chdir('..') 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') print('\033[1;34m[*] Bump version number\033[0m')
open('CMakeLists.txt', 'w').writelines(data) 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') 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') print('\033[1;34m[*] Update dev on main...\033[0m')
os.system('git checkout dev') subprocess.check_call(['git', 'checkout', 'dev'])
os.system('git merge master --ff') subprocess.check_call(['git', 'merge', 'master', '--ff'])
for i in range(len(data)): for i in range(len(data)):
m = re.match(r'^(#?)set\(COLOBOT_VERSION_(UNRELEASED|RELEASE_CODENAME)(.*)\)$', data[i]) m = re.match(r'^(#?)set\(COLOBOT_VERSION_(UNRELEASED|RELEASE_CODENAME)(.*)\)$', data[i])
if m: if m:
comment = (m.group(2) == 'RELEASE_CODENAME') comment = (m.group(2) == 'RELEASE_CODENAME')
data[i] = ('#' if comment else '')+'set(COLOBOT_VERSION_'+m.group(2)+m.group(3)+')\n' data[i] = ('#' if comment else '')+'set(COLOBOT_VERSION_'+m.group(2)+m.group(3)+')\n'
open('CMakeLists.txt', 'w').writelines(data) open('CMakeLists.txt', 'w').writelines(data)
os.system('git commit CMakeLists.txt -m "Post-release '+version+'"') subprocess.check_call(['git', 'commit', 'CMakeLists.txt', '-m', 'Post-release '+version])
os.system('git checkout master') 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')