Merge with master branch
authorGrigory Ustinov <grenka@altlinux.org>
Fri, 09 Nov 2018 14:15:22 +0300
changeset 14203 fae0dd90663b
parent 14202 ec07ddc1a4a4 (current diff)
parent 14200 abbb74b9cb62 (diff)
child 14204 97855d31c7a4
Merge with master branch
--- a/rust/fpnum/src/lib.rs	Fri Nov 09 14:12:00 2018 +0300
+++ b/rust/fpnum/src/lib.rs	Fri Nov 09 14:15:22 2018 +0300
@@ -364,6 +364,11 @@
     }
 
     #[inline]
+    pub fn is_zero(&self) -> bool {
+        self.x().is_zero() && self.y().is_zero()
+    }
+
+    #[inline]
     pub fn max_norm(&self) -> FPNum {
         std::cmp::max(self.x().abs(), self.y().abs())
     }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/rust/hwphysics/src/collision.rs	Fri Nov 09 14:15:22 2018 +0300
@@ -0,0 +1,128 @@
+use std::{
+    ops::RangeInclusive
+};
+
+use crate::{
+    common::{GearId, GearData, GearDataProcessor},
+    physics::PhysicsData,
+    grid::Grid
+};
+
+use fpnum::*;
+use integral_geometry::{
+    Point, Size, GridIndex
+};
+use land2d::Land2D;
+
+pub fn fppoint_round(point: &FPPoint) -> Point {
+    Point::new(point.x().round() as i32, point.y().round() as i32)
+}
+
+#[derive(PartialEq, Eq, Clone, Copy, Debug)]
+pub struct CircleBounds {
+    pub center: FPPoint,
+    pub radius: FPNum
+}
+
+impl CircleBounds {
+    pub fn intersects(&self, other: &CircleBounds) -> bool {
+        (other.center - self.center).is_in_range(self.radius + other.radius)
+    }
+
+    pub fn rows(&self) -> impl Iterator<Item = (usize, RangeInclusive<usize>)> {
+        let radius = self.radius.abs_round() as usize;
+        let center = Point::from_fppoint(&self.center);
+        (center.y as usize - radius..=center.y as usize + radius)
+            .map(move |row| (row, center.x as usize - radius..=center.x as usize + radius))
+    }
+}
+
+#[derive(PartialEq, Eq, Clone, Copy, Debug)]
+pub struct CollisionData {
+    pub bounds: CircleBounds
+}
+
+impl GearData for CollisionData {}
+
+#[derive(PartialEq, Eq, Clone, Copy, Debug)]
+pub struct ContactData {
+    pub elasticity: FPNum,
+    pub friction: FPNum
+}
+
+impl GearData for ContactData {}
+
+struct EnabledCollisionsCollection {
+    gear_ids: Vec<GearId>,
+    collisions: Vec<CollisionData>
+}
+
+impl EnabledCollisionsCollection {
+    fn new() -> Self {
+        Self {
+            gear_ids: Vec::new(),
+            collisions: Vec::new()
+        }
+    }
+
+    fn push(&mut self, gear_id: GearId, collision: CollisionData) {
+        self.gear_ids.push(gear_id);
+        self.collisions.push(collision);
+    }
+
+    fn iter(&self) -> impl Iterator<Item = (GearId, &CollisionData)> {
+        self.gear_ids.iter().cloned().zip(self.collisions.iter())
+    }
+}
+
+pub struct CollisionProcessor {
+    grid: Grid,
+    enabled_collisions: EnabledCollisionsCollection,
+
+    detected_collisions: DetectedCollisions,
+}
+
+pub struct DetectedCollisions {
+    pub pairs: Vec<(GearId, GearId)>,
+    pub positions: Vec<Point>
+}
+
+impl DetectedCollisions {
+    pub fn new(capacity: usize) -> Self {
+        Self {
+            pairs: Vec::with_capacity(capacity),
+            positions: Vec::with_capacity(capacity),
+        }
+    }
+
+    pub fn push(&mut self, contact_gear_id1: GearId, contact_gear_id2: GearId, position: &FPPoint) {
+        self.pairs.push((contact_gear_id1, contact_gear_id2));
+        self.positions.push(fppoint_round(&position));
+    }
+}
+
+impl CollisionProcessor {
+    pub fn new(size: Size) -> Self {
+        Self {
+            grid: Grid::new(size),
+            enabled_collisions: EnabledCollisionsCollection::new(),
+            detected_collisions: DetectedCollisions::new(0)
+        }
+    }
+
+    pub fn process(&mut self, land: &Land2D<u32>, updates: &crate::physics::PositionUpdates) {
+        self.grid.check_collisions(&mut self.detected_collisions);
+
+        for (gear_id, collision) in self.enabled_collisions.iter() {
+            if collision.bounds.rows().any(|(y, r)| (&land[y][r]).iter().any(|v| *v != 0)) {
+                self.detected_collisions.push(gear_id, 0, &collision.bounds.center)
+            }
+        }
+    }
+}
+
+impl GearDataProcessor<CollisionData> for CollisionProcessor {
+    fn add(&mut self, gear_id: GearId, gear_data: CollisionData) {
+        self.grid.insert_static(gear_id, &gear_data.bounds);
+    }
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/rust/hwphysics/src/common.rs	Fri Nov 09 14:15:22 2018 +0300
@@ -0,0 +1,10 @@
+pub type GearId = u16;
+pub trait GearData {}
+
+pub trait GearDataProcessor<T: GearData> {
+    fn add(&mut self, gear_id: GearId, gear_data: T);
+}
+
+pub trait GearDataAggregator<T: GearData> {
+    fn find_processor(&mut self) -> &mut GearDataProcessor<T>;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/rust/hwphysics/src/grid.rs	Fri Nov 09 14:15:22 2018 +0300
@@ -0,0 +1,91 @@
+use crate::{
+    common::GearId,
+    collision::{
+        fppoint_round,
+        CircleBounds,
+        DetectedCollisions
+    }
+};
+
+use integral_geometry::{
+    Point,
+    Size,
+    GridIndex
+};
+use fpnum::FPPoint;
+
+struct GridBin {
+    refs: Vec<GearId>,
+    static_entries: Vec<CircleBounds>,
+    dynamic_entries: Vec<CircleBounds>
+}
+
+impl GridBin {
+    fn new() -> Self {
+        Self {
+            refs: vec![],
+            static_entries: vec![],
+            dynamic_entries: vec![]
+        }
+    }
+}
+
+const GRID_BIN_SIZE: usize = 128;
+
+pub struct Grid {
+    bins: Vec<GridBin>,
+    space_size: Size,
+    bins_count: Size,
+    index: GridIndex
+}
+
+impl Grid {
+    pub fn new(size: Size) -> Self {
+        assert!(size.is_power_of_two());
+        let bins_count =
+            Size::new(size.width / GRID_BIN_SIZE,
+                      size.height / GRID_BIN_SIZE);
+
+        Self {
+            bins: (0..bins_count.area()).map(|_| GridBin::new()).collect(),
+            space_size: size,
+            bins_count,
+            index: Size::square(GRID_BIN_SIZE).to_grid_index()
+        }
+    }
+
+    fn bin_index(&self, position: &FPPoint) -> Point {
+        self.index.map(fppoint_round(position))
+    }
+
+    fn lookup_bin(&mut self, position: &FPPoint) -> &mut GridBin {
+        let index = self.bin_index(position);
+        &mut self.bins[index.x as usize * self.bins_count.width + index.y as usize]
+    }
+
+    pub fn insert_static(&mut self, gear_id: GearId, bounds: &CircleBounds) {
+        self.lookup_bin(&bounds.center).static_entries.push(*bounds)
+    }
+
+    pub fn insert_dynamic(&mut self, gear_id: GearId, bounds: &CircleBounds) {
+        self.lookup_bin(&bounds.center).dynamic_entries.push(*bounds)
+    }
+
+    pub fn check_collisions(&self, collisions: &mut DetectedCollisions) {
+        for bin in &self.bins {
+            for bounds in &bin.dynamic_entries {
+                for other in &bin.dynamic_entries {
+                    if bounds.intersects(other) && bounds != other {
+                        collisions.push(0, 0, &bounds.center)
+                    }
+                }
+
+                for other in &bin.static_entries {
+                    if bounds.intersects(other) {
+                        collisions.push(0, 0, &bounds.center)
+                    }
+                }
+            }
+        }
+    }
+}
\ No newline at end of file
--- a/rust/hwphysics/src/lib.rs	Fri Nov 09 14:12:00 2018 +0300
+++ b/rust/hwphysics/src/lib.rs	Fri Nov 09 14:15:22 2018 +0300
@@ -1,195 +1,108 @@
-use std::{
-    ops::RangeInclusive
-};
+mod common;
+mod physics;
+mod grid;
+mod collision;
 
-use fpnum::*;
-use integral_geometry::{
-    Point, Size, GridIndex
-};
+use fpnum::FPNum;
+use integral_geometry::Size;
 use land2d::Land2D;
 
-type Index = u16;
-
-#[derive(PartialEq, Eq, Clone, Copy, Debug)]
-struct PhysicsData {
-    position: FPPoint,
-    velocity: FPPoint,
-}
-
-#[derive(PartialEq, Eq, Clone, Copy, Debug)]
-struct  CollisionData {
-    bounds: CircleBounds
-}
-
-#[derive(PartialEq, Eq, Clone, Copy, Debug)]
-struct ContactData {
-    elasticity: FPNum,
-    friction: FPNum
-}
-
-pub struct PhysicsCollection {
-    positions: Vec<FPPoint>,
-    velocities: Vec<FPPoint>
-}
-
-impl PhysicsCollection {
-    fn push(&mut self, data: PhysicsData) {
-        self.positions.push(data.position);
-        self.velocities.push(data.velocity);
+use crate::{
+    common::{
+        GearId,
+        GearData,
+        GearDataAggregator,
+        GearDataProcessor
+    },
+    physics::{
+        PhysicsProcessor,
+        PhysicsData
+    },
+    collision::{
+        CollisionProcessor,
+        CollisionData,
+        ContactData
     }
-
-    fn iter_mut_pos(&mut self) -> impl Iterator<Item = (&mut FPPoint, &FPPoint)> {
-        self.positions.iter_mut().zip(self.velocities.iter())
-    }
-}
+};
 
 pub struct JoinedData {
+    gear_id: GearId,
     physics: PhysicsData,
     collision: CollisionData,
     contact: ContactData
 }
 
 pub struct World {
-    enabled_physics: PhysicsCollection,
-    disabled_physics: Vec<PhysicsData>,
-
-    enabled_collision: Vec<CollisionData>,
-    disabled_collision: Vec<CollisionData>,
-    grid: Grid,
-
-    physics_cleanup: Vec<PhysicsData>,
-    collision_output: Vec<(Index, Index)>,
-    land_collision_output: Vec<Index>
-}
-
-#[derive(PartialEq, Eq, Clone, Copy, Debug)]
-struct CircleBounds {
-    center: FPPoint,
-    radius: FPNum
-}
-
-impl CircleBounds {
-    pub fn intersects(&self, other: &CircleBounds) -> bool {
-        (other.center - self.center).is_in_range(self.radius + other.radius)
-    }
-
-    pub fn rows(&self) -> impl Iterator<Item = (usize, RangeInclusive<usize>)> {
-        let radius = self.radius.abs_round() as usize;
-        let center = Point::from_fppoint(&self.center);
-        (center.y as usize - radius..=center.y as usize + radius)
-            .map(move |row| (row, center.x as usize - radius..=center.x as usize + radius))
-    }
-}
-
-fn fppoint_round(point: &FPPoint) -> Point {
-    Point::new(point.x().round() as i32, point.y().round() as i32)
-}
-
-struct GridBin {
-    refs: Vec<Index>,
-    static_entries: Vec<CircleBounds>,
-    dynamic_entries: Vec<CircleBounds>
-}
-
-impl GridBin {
-    fn new() -> Self {
-        Self {
-            refs: vec![],
-            static_entries: vec![],
-            dynamic_entries: vec![]
-        }
-    }
+    physics: PhysicsProcessor,
+    collision: CollisionProcessor,
 }
 
-const GRID_BIN_SIZE: usize = 256;
-
-struct Grid {
-    bins: Vec<GridBin>,
-    space_size: Size,
-    bins_count: Size,
-    index: GridIndex
-}
-
-impl Grid {
-    fn new(size: Size) -> Self {
-        assert!(size.is_power_of_two());
-        let bins_count =
-            Size::new(size.width / GRID_BIN_SIZE,
-                      size.height / GRID_BIN_SIZE);
-
-        Self {
-            bins: (0..bins_count.area()).map(|_| GridBin::new()).collect(),
-            space_size: size,
-            bins_count,
-            index: Size::square(GRID_BIN_SIZE).to_grid_index()
-        }
-    }
-
-    fn bin_index(&self, position: &FPPoint) -> Point {
-        self.index.map(fppoint_round(position))
-    }
-
-    fn lookup_bin(&mut self, position: &FPPoint) -> &mut GridBin {
-        let index = self.bin_index(position);
-        &mut self.bins[index.x as usize * self.bins_count.width + index.y as usize]
-    }
-
-    fn insert_static(&mut self, index: Index, position: &FPPoint, bounds: &CircleBounds) {
-        self.lookup_bin(position).static_entries.push(*bounds)
-    }
-
-    fn insert_dynamic(&mut self, index: Index, position: &FPPoint, bounds: &CircleBounds) {
-        self.lookup_bin(position).dynamic_entries.push(*bounds)
-    }
-
-    fn check_collisions(&self, collisions: &mut Vec<(Index, Index)>) {
-        for bin in &self.bins {
-            for bounds in &bin.dynamic_entries {
-                for other in &bin.dynamic_entries {
-                    if bounds.intersects(other) && bounds != other {
-                        collisions.push((0, 0))
-                    }
-                }
-
-                for other in &bin.static_entries {
-                    if bounds.intersects(other) {
-                        collisions.push((0, 0))
-                    }
-                }
+macro_rules! processor_map {
+    ( $data_type: ident => $field: ident ) => {
+        impl GearDataAggregator<$data_type> for World {
+            fn find_processor(&mut self) -> &mut GearDataProcessor<$data_type> {
+                &mut self.$field
             }
         }
     }
 }
 
-impl World {
-    pub fn step(&mut self, time_step: FPNum, land: &Land2D<u32>) {
-        for (pos, vel) in self.enabled_physics.iter_mut_pos() {
-            *pos += *vel
-        }
+processor_map!(PhysicsData => physics);
+processor_map!(CollisionData => collision);
 
-        self.grid.check_collisions(&mut self.collision_output);
-    }
-
-    fn check_land_collisions(&mut self, land: &Land2D<u32>) {
-        for collision in &self.enabled_collision {
-            if collision.bounds.rows().any(|(y, r)| (&land[y][r]).iter().any(|v| *v != 0)) {
-                self.land_collision_output.push(0)
-            }
+impl World {
+    pub fn new(world_size: Size) -> Self {
+        Self {
+            physics: PhysicsProcessor::new(),
+            collision: CollisionProcessor::new(world_size)
         }
     }
 
-    pub fn add_gear(&mut self, data: JoinedData) {
-        if data.physics.velocity == FPPoint::zero() {
-            self.disabled_physics.push(data.physics);
-            self.grid.insert_static(0, &data.physics.position, &data.collision.bounds);
-        } else {
-            self.enabled_physics.push(data.physics);
-            self.grid.insert_dynamic(0, &data.physics.position, &data.collision.bounds);
-        }
+    pub fn step(&mut self, time_step: FPNum, land: &Land2D<u32>) {
+        let updates = self.physics.process(time_step);
+        self.collision.process(land, &updates);
+    }
+
+    pub fn add_gear_data<T>(&mut self, gear_id: GearId, data: T)
+        where T: GearData,
+              Self: GearDataAggregator<T>
+    {
+        self.find_processor().add(gear_id, data);
     }
 }
 
 #[cfg(test)]
 mod tests {
+    use crate::{
+        World,
+        physics::PhysicsData,
+        collision::{CollisionData, CircleBounds}
+    };
+    use fpnum::{FPNum, FPPoint, fp};
+    use integral_geometry::Size;
+    use land2d::Land2D;
 
+    #[test]
+    fn data_flow() {
+        let world_size = Size::new(2048, 2048);
+
+        let mut world = World::new(world_size);
+        let gear_id = 46631;
+
+        world.add_gear_data(gear_id, PhysicsData {
+            position: FPPoint::zero(),
+            velocity: FPPoint::unit_y()
+        });
+
+        world.add_gear_data(gear_id, CollisionData {
+            bounds: CircleBounds {
+                center: FPPoint::zero(),
+                radius: fp!(10)
+            }
+        });
+
+        let land = Land2D::new(Size::new(world_size.width - 2, world_size.height - 2), 0);
+
+        world.step(fp!(1), &land);
+    }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/rust/hwphysics/src/physics.rs	Fri Nov 09 14:15:22 2018 +0300
@@ -0,0 +1,134 @@
+use crate::{
+    common::{GearId, GearData, GearDataProcessor}
+};
+use fpnum::*;
+use integral_geometry::{
+    Point, Size, GridIndex
+};
+
+#[derive(PartialEq, Eq, Clone, Copy, Debug)]
+pub struct PhysicsData {
+    pub position: FPPoint,
+    pub velocity: FPPoint,
+}
+
+impl GearData for PhysicsData {}
+
+pub struct DynamicPhysicsCollection {
+    gear_ids: Vec<GearId>,
+    positions: Vec<FPPoint>,
+    velocities: Vec<FPPoint>,
+}
+
+impl DynamicPhysicsCollection {
+    fn new() -> Self {
+        Self {
+            gear_ids: Vec::new(),
+            positions: Vec::new(),
+            velocities: Vec::new()
+        }
+    }
+
+    fn len(&self) -> usize {
+        self.gear_ids.len()
+    }
+
+    fn push(&mut self, id: GearId, physics: PhysicsData) {
+        self.gear_ids.push(id);
+        self.positions.push(physics.position);
+        self.velocities.push(physics.velocity);
+    }
+
+    fn iter_pos_update(&mut self) -> impl Iterator<Item = (GearId, (&mut FPPoint, &FPPoint))> {
+        self.gear_ids.iter().cloned()
+            .zip(self.positions.iter_mut()
+                .zip(self.velocities.iter()))
+    }
+}
+
+pub struct StaticPhysicsCollection {
+    gear_ids: Vec<GearId>,
+    positions: Vec<FPPoint>
+}
+
+impl StaticPhysicsCollection {
+    fn new() -> Self {
+        Self {
+            gear_ids: Vec::new(),
+            positions: Vec::new()
+        }
+    }
+
+    fn push(&mut self, gear_id: GearId, physics: PhysicsData) {
+        self.gear_ids.push(gear_id);
+        self.positions.push(physics.position);
+    }
+}
+
+pub struct PhysicsProcessor {
+    dynamic_physics: DynamicPhysicsCollection,
+    static_physics: StaticPhysicsCollection,
+
+    physics_cleanup: Vec<GearId>,
+    position_updates: PositionUpdates
+}
+
+pub struct PositionUpdates {
+    pub gear_ids: Vec<GearId>,
+    pub positions: Vec<FPPoint>
+}
+
+impl PositionUpdates {
+    pub fn new(capacity: usize) -> Self {
+        Self {
+            gear_ids: Vec::with_capacity(capacity),
+            positions: Vec::with_capacity(capacity),
+        }
+    }
+
+    pub fn push(&mut self, gear_id: GearId, position: &FPPoint) {
+        self.gear_ids.push(gear_id);
+        self.positions.push(*position);
+    }
+}
+
+impl PhysicsProcessor {
+    pub fn new() -> Self {
+        PhysicsProcessor {
+            dynamic_physics: DynamicPhysicsCollection::new(),
+            static_physics: StaticPhysicsCollection::new(),
+            physics_cleanup: Vec::new(),
+            position_updates: PositionUpdates::new(0)
+        }
+    }
+
+    pub fn process(&mut self, time_step: FPNum) -> &PositionUpdates {
+        for (gear_id, (pos, vel)) in self.dynamic_physics.iter_pos_update() {
+            *pos += *vel * time_step;
+            if !vel.is_zero() {
+                self.position_updates.push(gear_id, pos)
+            } else {
+                self.physics_cleanup.push(gear_id)
+            }
+        }
+        &self.position_updates
+    }
+
+    pub fn push(&mut self, gear_id: GearId, physics_data: PhysicsData) {
+        if physics_data.velocity.is_zero() {
+            self.static_physics.push(gear_id, physics_data);
+        } else {
+            self.dynamic_physics.push(gear_id, physics_data);
+        }
+    }
+}
+
+impl GearDataProcessor<PhysicsData> for PhysicsProcessor {
+    fn add(&mut self, gear_id: GearId, gear_data: PhysicsData) {
+        if gear_data.velocity.is_zero() {
+            self.static_physics.push(gear_id, gear_data);
+        } else {
+            self.dynamic_physics.push(gear_id, gear_data);
+        }
+    }
+}
\ No newline at end of file
--- a/rust/integral-geometry/src/lib.rs	Fri Nov 09 14:12:00 2018 +0300
+++ b/rust/integral-geometry/src/lib.rs	Fri Nov 09 14:15:22 2018 +0300
@@ -152,6 +152,11 @@
     }
 
     #[inline]
+    pub fn transpose(&self) -> Self {
+        Self::new(self.height, self.width)
+    }
+
+    #[inline]
     pub fn to_mask(&self) -> SizeMask {
         SizeMask::new(*self)
     }
--- a/rust/lib-hedgewars-engine/src/command.rs	Fri Nov 09 14:12:00 2018 +0300
+++ b/rust/lib-hedgewars-engine/src/command.rs	Fri Nov 09 14:15:22 2018 +0300
@@ -1,4 +1,3 @@
 pub enum Command {
-    SetAmmo(String),
     ChatMessage(String),
 }
--- a/rust/lib-hedgewars-engine/src/engine_message.rs	Fri Nov 09 14:12:00 2018 +0300
+++ b/rust/lib-hedgewars-engine/src/engine_message.rs	Fri Nov 09 14:15:22 2018 +0300
@@ -11,6 +11,7 @@
     Up(KeystrokeAction),
     Down(KeystrokeAction),
     Precise(KeystrokeAction),
+    Attack(KeystrokeAction),
     NextTurn,
     Switch,
     Empty,
@@ -30,18 +31,88 @@
     Pong,
     Say(String),
     Taunt(u8),
-    ExecCommand(Command),
-    GameType(u8),// TODO: use enum
+    GameType(u8),
     Warning(String),
     StopSyncing,
-    ConfigRequest,
     GameOver,
     GameInterrupted,
+    GameSetupChecksum(String),
+}
+
+pub enum ConfigEngineMessage {
+    ConfigRequest,
+    SetAmmo(String),
+    SetScript(String),
+    SetScriptParam(String),
+    Spectate,
+    TeamLocality(bool),
+    SetMap(String),
+    SetTheme(String),
+    SetSeed(String),
+    SetTemplateFilter(String),
+    SetMapGenerator(String),
+    SetFeatureSize(u8),
+    SetDelay(u32),
+    SetReadyDelay(u32),
+    SetCratesFrequency(u8),
+    SetHealthCrateProbability(u8),
+    SetHealthCratesNumber(u8),
+    SetRoundsTilSuddenDeath(u8),
+    SetSuddenDeathWaterRiseSpeed(u8),
+    SetSuddenDeathHealthDecreaseRate(u8),
+    SetDamageMultiplier(u32),
+    SetRopeLength(u32),
+    SetGetawayTime(u32),
+    SetDudMinesPercent(u8),
+    SetMinesNumber(u32),
+    SetAirMinesNumber(u32),
+    SetBarrelsNumber(u32),
+    SetTurnTime(u32),
+    SetMinesTime(u32),
+    SetWorldEdge(u8),
+    Draw, // TODO
+    SetVoicePack(String),
+    AddHedgehog(String, u8, u32),
+    AddTeam(String, u8),
+    SetHedgehogCoordinates(i32, i32),
+    SetFort(String),
+    SetGrave(String),
+    SetHat(String),
+    SetFlag(String),
+    SetOwner(String),
+    SetOneClanMode(bool),
+    SetMultishootMode(bool),
+    SetSolidLand(bool),
+    SetBorders(bool),
+    SetDivideTeams(bool),
+    SetLowGravity(bool),
+    SetLaserSight(bool),
+    SetInvulnerability(bool),
+    SetHealthReset(bool),
+    SetVampiric(bool),
+    SetKarma(bool),
+    SetArtilleryMode(bool),
+    SetHedgehogSwitch(bool),
+    SetRandomOrder(bool),
+    SetKingMode(bool),
+    SetPlaceHedgehog(bool),
+    SetSharedAmmo(bool),
+    SetGirdersEnabled(bool),
+    SetLandObjectsEnabled(bool),
+    SetAISurvivalMode(bool),
+    SetInfiniteAttack(bool),
+    SetResetWeapons(bool),
+    SetAmmoPerHedgehog(bool),
+    SetWindMode(u8),
+    SetTagTeam(bool),
+    SetBottomBorder(bool),
+    SetShoppaBorder(bool),
 }
 
 pub enum EngineMessage {
     Synced(SyncedEngineMessage, u32),
     Unsynced(UnsyncedEngineMessage),
+    Config(ConfigEngineMessage),
 }
 
 impl EngineMessage {
--- a/rust/mapgen/src/lib.rs	Fri Nov 09 14:12:00 2018 +0300
+++ b/rust/mapgen/src/lib.rs	Fri Nov 09 14:15:22 2018 +0300
@@ -141,6 +141,7 @@
         if let Some(border_sprite) = theme.border_texture() {
             assert!(border_sprite.height() <= 512);
             let border_width = (border_sprite.height() / 2) as u8;
+            let border_sprite = border_sprite.to_tiled();
 
             let mut offsets = vec![255u8; land.width()];
 
--- a/rust/mapgen/src/theme.rs	Fri Nov 09 14:12:00 2018 +0300
+++ b/rust/mapgen/src/theme.rs	Fri Nov 09 14:15:22 2018 +0300
@@ -23,18 +23,18 @@
 
 impl ThemeSprite {
     #[inline]
+    pub fn size(&self) -> Size {
+        self.pixels.size()
+    }
+
+    #[inline]
     pub fn width(&self) -> usize {
-        self.pixels.size().width
+        self.size().width
     }
 
     #[inline]
     pub fn height(&self) -> usize {
-        self.pixels.size().height
-    }
-
-    #[inline]
-    pub fn bounds(&self) -> Size {
-        self.pixels.size()
+        self.size().height
     }
 
     #[inline]
@@ -51,6 +51,65 @@
     pub fn get_pixel(&self, x: usize, y: usize) -> u32 {
         self.pixels[y][x]
     }
+
+    pub fn to_transposed(&self) -> ThemeSprite {
+        let size = self.size().transpose();
+        let mut pixels = Vec2D::new(size, 0u32);
+        for (y, row) in self.pixels.rows().enumerate() {
+            for (x, v) in row.iter().enumerate() {
+                pixels[x][y] = *v;
+            }
+        }
+        ThemeSprite { pixels }
+    }
+
+    pub fn to_tiled(&self) -> TiledSprite {
+        let size = self.size();
+        assert!(size.is_power_of_two());
+        let tile_width_shift = size.width.trailing_zeros() as usize + 2;
+        let mut pixels = vec![0u32; size.area()];
+
+        for (y, row) in self.pixels.rows().enumerate() {
+            for (x, v) in row.iter().enumerate() {
+                pixels[get_tiled_index(x, y, tile_width_shift)] = *v;
+            }
+        }
+
+        TiledSprite { tile_width_shift, size, pixels }
+    }
+}
+
+#[inline]
+fn get_tiled_index(x: usize, y: usize, tile_width_shift: usize) -> usize {
+    (((y >> 2) << tile_width_shift) + ((x >> 2) << 4)) + ((y & 0b11) << 2) + (x & 0b11)
+}
+
+pub struct TiledSprite {
+    tile_width_shift: usize,
+    size: Size,
+    pixels: Vec<u32>
+}
+
+impl TiledSprite {
+    #[inline]
+    pub fn size(&self) -> Size {
+        self.size
+    }
+
+    #[inline]
+    pub fn width(&self) -> usize {
+        self.size().width
+    }
+
+    #[inline]
+    pub fn height(&self) -> usize {
+        self.size().height
+    }
+
+    #[inline]
+    pub fn get_pixel(&self, x: usize, y: usize) -> u32 {
+        self.pixels[get_tiled_index(x, y, self.tile_width_shift)]
+    }
 }
 
 pub struct Theme {
--- a/share/hedgewars/Data/Locale/campaigns_uk.txt	Fri Nov 09 14:12:00 2018 +0300
+++ b/share/hedgewars/Data/Locale/campaigns_uk.txt	Fri Nov 09 14:15:22 2018 +0300
@@ -6,7 +6,7 @@
 
 A_Classic_Fairytale-united.desc="Після довгої мандрівки Протікайко повернувся до села. Але немає коли відпочивати. Треба захистити село від нападу канібалів."
 
-A_Classic_Fairytale-backstab.desc="The monstrous cannibals are hunting Leaks a lot and his friends. Defeat them once again and protect your allies. Use your resources accordingly to defeat the incoming enemies!"
+A_Classic_Fairytale-backstab.desc="Жорстокі канібали полюють на Протікайка і його друзів. Подолай їх знов і захисти союзників. Використовуй наявні ресурси розумно для подолання атакуючих ворогів!"
 
 A_Classic_Fairytale-dragon.desc="Протікайту треба перебратись на інший берег озера. Стань майстром мотузки і уникай пострілів ворога."
 
@@ -16,17 +16,17 @@
 
 A_Classic_Fairytale-enemy.desc="Який поворот! Протікайку треба битись пліч-о-пліч з… “канібалами” протиспільного ворога. Злих кіборгів!"
 
-A_Classic_Fairytale-epil.desc="Вітання! Протікайко нарешті може мирно жити і бути поцінованим новими друзями і йоо племенем. Гордись доясненнями! Ти можеш пройти попередні місії знов і глянути на інші кінцівки."
+A_Classic_Fairytale-epil.desc="Вітання! Протікайко нарешті може мирно жити і бути поцінованим новими друзями і його племенем. Гордись досягненнями! Ти можеш пройти попередні місії знов і глянути на інші кінцівки."
 
 A_Space_Adventure-cosmos.desc="На планету їжаків, Їжакію, незабаром має впасти гігантський метеорит. В боротьбі за виживання вам потрібно провести кращого пілота PAotH, Їжака Соло, в подорож сусідніми планетами щоб знайти всі 4 частини давно загубленого антигравітаційного пристрою!"
 A_Space_Adventure-moon01.desc="Hog Solo has landed on the moon to refuel his saucer but professor Hogevil has gone there first and set an ambush! Rescue the captured PAotH researchers and drive professor Hogevil away!"
 A_Space_Adventure-moon02.desc="Hog Solo visits an hermit, old PAotH veteran, who lives in moon in order to gather some intel about Pr. Hogevil. However, he has to beat the hermit, Soneek the Crazy Runner, in a chase game first!"
-A_Space_Adventure-ice01.desc="Welcome to the planet of ice. Here, it's so cold that most of Hog Solo's weapons won't work. You have to get the lost part from the bandit leader Thanta using the weapons that you'll find there!"
+A_Space_Adventure-ice01.desc="Вітаємо на планеті льоду. Тут настільки холодно, що більшість зброї Їжака Соло не працює. You have to get the lost part from the bandit leader Thanta using the weapons that you'll find there!"
 A_Space_Adventure-ice02.desc="Hog Solo couldn't just visit the Ice Planet without visiting the Olympic stadium of saucer flying! In this mission you can prove your flying skills and claim your place between the best!"
 A_Space_Adventure-desert01.desc="You have landed to the planet of sand! Hog Solo has to find the missing part in the underground tunnels. Be careful as vicious smugglers await to attack and rob you!"
 A_Space_Adventure-desert02.desc="Hog Solo was searching for the part in this tunnel when it unexpectedly start getting flooded! Get to the surface as soon as possible and be careful not to trigger a mine."
 A_Space_Adventure-desert03.desc="Hog Solo has some time to fly his RC plane and have some fun. Fly the RC plane and hit all the targets!"
-A_Space_Adventure-fruit01.desc="In the fruit planet things aren't going so well. Hogs aren't collecting fruits but they are preparing for battle. You'll have to choose if you'll fight or if you'll flee."
+A_Space_Adventure-fruit01.desc="На фруктовій планеті справи кепські. Їжаки не збирають фрукти але готуються до бою. You'll have to choose if you'll fight or if you'll flee."
 A_Space_Adventure-fruit02.desc="Hog Solo gets closer to the lost part in the Fruit Planet. Will Captain Lime help him acquire the part or not?"
 A_Space_Adventure-fruit03.desc="Hog Solo got lost and got ambushed by the Red Strawberries. Help him eliminate them and win some extra ammo for the Getting to the device mission."
 A_Space_Adventure-death01.desc="In the Death Planet, the most infertile planet around, Hog Solo is very close to get the last part of the device! However an unpleasant surprise awaits him..."
--- a/share/hedgewars/Data/Locale/hedgewars_uk.ts	Fri Nov 09 14:12:00 2018 +0300
+++ b/share/hedgewars/Data/Locale/hedgewars_uk.ts	Fri Nov 09 14:15:22 2018 +0300
@@ -10,73 +10,73 @@
     <message>
         <source>Hedgewars %1</source>
         <extracomment>%1 contains Hedgewars&apos; version number</extracomment>
-        <translation type="unfinished">Hedgewars %1</translation>
+        <translation>Hedgewars %1</translation>
     </message>
     <message>
         <source>Revision %1 (%2)</source>
-        <translation type="unfinished"></translation>
+        <translation>Ревізія %1 (%2)</translation>
     </message>
     <message>
         <source>Visit our homepage: %1</source>
-        <translation type="unfinished"></translation>
+        <translation>Наша домашня сторінка: %1</translation>
     </message>
     <message>
         <source>This program is distributed under the %1.</source>
-        <translation type="unfinished">Ця програма поширюється згідно з %1.</translation>
+        <translation>Ця програма поширюється згідно з %1.</translation>
     </message>
     <message>
         <source>GNU GPL v2</source>
         <extracomment>Short for “GNU General Public License version 2”</extracomment>
-        <translation type="unfinished"></translation>
+        <translation>GNU GPL v2</translation>
     </message>
     <message>
         <source>Dependency versions:</source>
         <extracomment>For the version numbers of Hedgewars&apos; software dependencies</extracomment>
-        <translation type="unfinished"></translation>
+        <translation>Версії залежностей:</translation>
     </message>
     <message>
         <source>&lt;a href=&quot;https://gcc.gnu.org&quot;&gt;GCC&lt;/a&gt;: %1</source>
-        <translation type="unfinished"></translation>
+        <translation>&lt;a href=&quot;https://gcc.gnu.org&quot;&gt;GCC&lt;/a&gt;: %1</translation>
     </message>
     <message>
         <source>&lt;a href=&quot;https://www.libsdl.org/&quot;&gt;SDL2&lt;/a&gt;: %1.%2.%3</source>
-        <translation type="unfinished"></translation>
+        <translation>&lt;a href=&quot;https://www.libsdl.org/&quot;&gt;SDL2&lt;/a&gt;: %1.%2.%3</translation>
     </message>
     <message>
         <source>&lt;a href=&quot;https://www.libsdl.org/&quot;&gt;SDL2_mixer&lt;/a&gt;: %1.%2.%3</source>
-        <translation type="unfinished"></translation>
+        <translation>&lt;a href=&quot;https://www.libsdl.org/&quot;&gt;SDL2_mixer&lt;/a&gt;: %1.%2.%3</translation>
     </message>
     <message>
         <source>&lt;a href=&quot;https://www.libsdl.org/&quot;&gt;SDL2_net&lt;/a&gt;: %1.%2.%3</source>
-        <translation type="unfinished"></translation>
+        <translation>&lt;a href=&quot;https://www.libsdl.org/&quot;&gt;SDL2_net&lt;/a&gt;: %1.%2.%3</translation>
     </message>
     <message>
         <source>&lt;a href=&quot;https://www.libsdl.org/&quot;&gt;SDL2_image&lt;/a&gt;: %1.%2.%3</source>
-        <translation type="unfinished"></translation>
+        <translation>&lt;a href=&quot;https://www.libsdl.org/&quot;&gt;SDL2_image&lt;/a&gt;: %1.%2.%3</translation>
     </message>
     <message>
         <source>&lt;a href=&quot;https://www.libsdl.org/&quot;&gt;SDL2_ttf&lt;/a&gt;: %1.%2.%3</source>
-        <translation type="unfinished"></translation>
+        <translation>&lt;a href=&quot;https://www.libsdl.org/&quot;&gt;SDL2_ttf&lt;/a&gt;: %1.%2.%3</translation>
     </message>
     <message>
         <source>&lt;a href=&quot;https://www.qt.io/developers/&quot;&gt;Qt&lt;/a&gt;: %1</source>
-        <translation type="unfinished"></translation>
+        <translation>&lt;a href=&quot;https://www.qt.io/developers/&quot;&gt;Qt&lt;/a&gt;: %1</translation>
     </message>
     <message>
         <source>&lt;a href=&quot;https://libav.org&quot;&gt;libavcodec&lt;/a&gt;: %1.%2.%3</source>
-        <translation type="unfinished"></translation>
+        <translation>&lt;a href=&quot;https://libav.org&quot;&gt;libavcodec&lt;/a&gt;: %1.%2.%3</translation>
     </message>
     <message>
         <source>&lt;a href=&quot;https://libav.org&quot;&gt;libavformat&lt;/a&gt;: %1.%2.%3</source>
-        <translation type="unfinished"></translation>
+        <translation>&lt;a href=&quot;https://libav.org&quot;&gt;libavformat&lt;/a&gt;: %1.%2.%3</translation>
     </message>
     <message>
         <source>&lt;a href=&quot;https://libav.org&quot;&gt;libavutil&lt;/a&gt;: %1.%2.%3</source>
-        <translation type="unfinished"></translation>
+        <translation>&lt;a href=&quot;https://libav.org&quot;&gt;libavutil&lt;/a&gt;: %1.%2.%3</translation>
     </message>
     <message>
         <source>&lt;a href=&quot;https://icculus.org/physfs/&quot;&gt;PhysFS&lt;/a&gt;: %1.%2.%3</source>
-        <translation type="unfinished"></translation>
+        <translation>&lt;a href=&quot;https://icculus.org/physfs/&quot;&gt;PhysFS&lt;/a&gt;: %1.%2.%3</translation>
     </message>
 </context>
 <context>
@@ -138,15 +138,15 @@
     </message>
     <message>
         <source>Ban player</source>
-        <translation type="unfinished"></translation>
+        <translation>Забанити гравця</translation>
     </message>
     <message>
         <source>Please specify an IP address.</source>
-        <translation type="unfinished"></translation>
+        <translation>Вкажіть IP адресу.</translation>
     </message>
     <message>
         <source>Please specify a nickname.</source>
-        <translation type="unfinished"></translation>
+        <translation>Вкажіть нікнейм.</translation>
     </message>
 </context>
 <context>
@@ -188,11 +188,11 @@
     </message>
     <message>
         <source>Feedback</source>
-        <translation type="unfinished">Відгук</translation>
+        <translation>Відгук</translation>
     </message>
     <message>
         <source>This is optional, but this information might help us to resolve bugs and other technical problems.</source>
-        <translation type="unfinished"></translation>
+        <translation>Це необов&apos;язково, але ця інформація може допомогти нам у вирішенні проблем.</translation>
     </message>
 </context>
 <context>
@@ -249,19 +249,19 @@
     </message>
     <message>
         <source>New</source>
-        <translation type="unfinished">Нова</translation>
+        <translation>Нова</translation>
     </message>
     <message>
         <source>Copy of %1</source>
-        <translation type="unfinished"></translation>
+        <translation>Копія %1</translation>
     </message>
     <message>
         <source>New (%1)</source>
-        <translation type="unfinished"></translation>
+        <translation>Нова (%1)</translation>
     </message>
     <message>
         <source>Copy of %1 (%2)</source>
-        <translation type="unfinished"></translation>
+        <translation>Копія %1 (%2)</translation>
     </message>
 </context>
 <context>
@@ -285,8 +285,8 @@
         <source>%1 hour</source>
         <translation>
             <numerusform>%1 година</numerusform>
-            <numerusform></numerusform>
-            <numerusform></numerusform>
+            <numerusform>%1 години</numerusform>
+            <numerusform>%1 годин</numerusform>
         </translation>
     </message>
     <message numerus="yes">
@@ -301,8 +301,8 @@
         <source>%1 day</source>
         <translation>
             <numerusform>%1 день</numerusform>
-            <numerusform></numerusform>
-            <numerusform></numerusform>
+            <numerusform>%1 дні</numerusform>
+            <numerusform>%1 днів</numerusform>
         </translation>
     </message>
     <message numerus="yes">
@@ -334,52 +334,52 @@
     <message>
         <source>Usage</source>
         <comment>command-line</comment>
-        <translation type="unfinished"></translation>
+        <translation>Використання</translation>
     </message>
     <message>
         <source>OPTION</source>
         <comment>command-line</comment>
-        <translation type="unfinished"></translation>
+        <translation>OPTION</translation>
     </message>
     <message>
         <source>CONNECTSTRING</source>
         <comment>command-line</comment>
-        <translation type="unfinished"></translation>
+        <translation>CONNECTSTRING</translation>
     </message>
     <message>
         <source>Options</source>
         <comment>command-line</comment>
-        <translation type="unfinished"></translation>
+        <translation>Опції</translation>
     </message>
     <message>
         <source>Display this help</source>
         <comment>command-line</comment>
-        <translation type="unfinished"></translation>
+        <translation>Показати цю довідку</translation>
     </message>
     <message>
         <source>Custom path for configuration data and user data</source>
         <comment>command-line</comment>
-        <translation type="unfinished"></translation>
+        <translation>Користувацький шлях до даних конфігурації та даних користувача</translation>
     </message>
     <message>
         <source>Custom path to the game data folder</source>
         <comment>command-line</comment>
-        <translation type="unfinished"></translation>
+        <translation>Користувацький шлях до теки даних гри</translation>
     </message>
     <message>
         <source>Hedgewars can use a %1 (e.g. &quot;%2&quot;) to connect on start.</source>
         <comment>command-line</comment>
-        <translation type="unfinished"></translation>
+        <translation>Hedgewars може використовувати %1 (напр. &quot;%2&quot;) щоб під&apos;єднуватися на старті.</translation>
     </message>
     <message>
         <source>Malformed option argument: %1</source>
         <comment>command-line</comment>
-        <translation type="unfinished"></translation>
+        <translation>Невірний аргумент опції: %1</translation>
     </message>
     <message>
         <source>Unknown option argument: %1</source>
         <comment>command-line</comment>
-        <translation type="unfinished"></translation>
+        <translation>Невідомий аргумент опції: %1</translation>
     </message>
 </context>
 <context>
@@ -445,15 +445,15 @@
     </message>
     <message>
         <source>Chat log</source>
-        <translation type="unfinished"></translation>
+        <translation>Журнал чату</translation>
     </message>
     <message>
         <source>Enter chat messages here and send them with [Enter]</source>
-        <translation type="unfinished"></translation>
+        <translation>Вводіть повідомлення чату тут і надсилайте їх натиснувши [Enter]</translation>
     </message>
     <message>
         <source>List of players</source>
-        <translation type="unfinished"></translation>
+        <translation>Перелік гравців</translation>
     </message>
 </context>
 <context>
@@ -579,34 +579,34 @@
     <message>
         <source>The room is protected with password.
 Please, enter the password:</source>
-        <translation type="unfinished">Кімната захищена паролем.
+        <translation>Кімната захищена паролем.
 Будь ласка, введіть пароль:</translation>
     </message>
     <message>
         <source>Team 1</source>
-        <translation type="unfinished"></translation>
+        <translation>Команда 1</translation>
     </message>
     <message>
         <source>Team %1</source>
         <extracomment>Default team name</extracomment>
-        <translation type="unfinished"></translation>
+        <translation>Команда %1</translation>
     </message>
     <message>
         <source>Computer %1</source>
         <extracomment>Default computer team name</extracomment>
-        <translation type="unfinished"></translation>
+        <translation>Комп&apos;ютер %1</translation>
     </message>
     <message>
         <source>Unknown network error (possibly missing SSL library).</source>
-        <translation type="unfinished"></translation>
+        <translation>Невідома помилка мережі (можливо відсутня бібліотека SSL).</translation>
     </message>
     <message>
         <source>This feature requires an Internet connection, but you don&apos;t appear to be online (error code: %1).</source>
-        <translation type="unfinished"></translation>
+        <translation>Ця функція потребує підключення до Інтернету, але ви, здається, не знаходитесь в мережі (код помилки: %1).</translation>
     </message>
     <message>
         <source>Internal error: Reply object is invalid.</source>
-        <translation type="unfinished"></translation>
+        <translation>Внутрішня помилка: об&apos;єкт відповіді недійсний.</translation>
     </message>
 </context>
 <context>
@@ -629,14 +629,21 @@
 
 Last engine message:
 %1</source>
-        <translation type="unfinished"></translation>
+        <translation>Виникла фатальна ПОМИЛКА! Ігровий двигун довелося зупинити.
+
+Нам дуже шкода за незручності. :-(
+
+Якщо це триватиме, натисніть кнопку &quot;Зворотний зв&apos;язок&quot; у головному меню!
+
+Останнє повідомлення двигуна:
+%1</translation>
     </message>
 </context>
 <context>
     <name>HWHostPortDialog</name>
     <message>
         <source>Connect to server</source>
-        <translation type="unfinished"></translation>
+        <translation>Під&apos;єднатись до сервера</translation>
     </message>
 </context>
 <context>
@@ -772,11 +779,11 @@
     </message>
     <message>
         <source>Style:</source>
-        <translation type="unfinished"></translation>
+        <translation>Стиль:</translation>
     </message>
     <message>
         <source>Forts</source>
-        <translation type="unfinished"></translation>
+        <translation>Форти</translation>
     </message>
     <message>
         <source>View and edit the seed, the source of randomness in the game</source>
@@ -784,11 +791,11 @@
     </message>
     <message>
         <source>Randomize the theme</source>
-        <translation type="unfinished"></translation>
+        <translation>Випадкова тема</translation>
     </message>
     <message>
         <source>Choose a theme</source>
-        <translation type="unfinished"></translation>
+        <translation>Виберіть тему</translation>
     </message>
     <message>
         <source>Randomize the map, theme and seed</source>
@@ -812,15 +819,15 @@
     </message>
     <message>
         <source>Adjust the complexity of the generated map</source>
-        <translation type="unfinished"></translation>
+        <translation>Вкажіть складність згенерованої мапи</translation>
     </message>
     <message>
         <source>Adjust the distance between forts</source>
-        <translation type="unfinished"></translation>
+        <translation>Вкажіть відстань між фортами</translation>
     </message>
     <message>
         <source>Click to edit</source>
-        <translation type="unfinished"></translation>
+        <translation>Клацніть для зміни</translation>
     </message>
 </context>
 <context>
@@ -892,15 +899,15 @@
     </message>
     <message>
         <source>Server authentication error</source>
-        <translation type="unfinished"></translation>
+        <translation>Помилка автентифікації на сервері</translation>
     </message>
     <message>
         <source>Reason:</source>
-        <translation type="unfinished"></translation>
+        <translation>Причина:</translation>
     </message>
     <message>
         <source>The connection was refused by the official server or timed out. Something seems to be wrong with the official server at the moment. This might be a temporary problem. Please try again later.</source>
-        <translation type="unfinished"></translation>
+        <translation>Зв&apos;язок розірвано офіційним сервером або закінчився час очікування. Здається на даний момент є проблеми з офіційним сервером. Це може бути тимчасовою проблемою. Будь ласка спробуйте пізніше.</translation>
     </message>
     <message>
         <source>The connection was refused by the host or timed out. This might have one of the following reasons:
@@ -909,7 +916,12 @@
 - There is a temporary network problem
 
 Please check the host name and port settings and/or try again later.</source>
-        <translation type="unfinished"></translation>
+        <translation>З&apos;єднання розірвано хостом або закінчився час очікування. Це може мати одну з наступних причин:
+- Серверна частина Hedgewars наразі не працює на хості
+- Вказаний невірний номер порту
+- Існує тимчасова проблема з мережею
+
+Перевірте налаштування імені хоста та порту та/або повторіть спробу пізніше.</translation>
     </message>
 </context>
 <context>
@@ -938,7 +950,7 @@
     </message>
     <message>
         <source>New Account</source>
-        <translation type="unfinished"></translation>
+        <translation>Новий акаунт</translation>
     </message>
 </context>
 <context>
@@ -975,7 +987,7 @@
     </message>
     <message>
         <source>Choose a hat</source>
-        <translation type="unfinished"></translation>
+        <translation>Виберіть капелюх</translation>
     </message>
 </context>
 <context>
@@ -1017,33 +1029,33 @@
     <message>
         <source>Duration: %1min %2s</source>
         <extracomment>Duration in minutes and seconds (SI units)</extracomment>
-        <translation type="unfinished"></translation>
+        <translation>Тривалість: %1хв %2с</translation>
     </message>
     <message>
         <source>Video: %1x%2, %3 FPS, %4</source>
         <extracomment>Video metadata. %1 = video width, %2 = video height, %3 = frames per second = %4 = decoder name</extracomment>
-        <translation type="unfinished"></translation>
+        <translation>Відео: %1x%2, %3 FPS, %4</translation>
     </message>
     <message>
         <source>Video: %1x%2, %3</source>
         <extracomment>Video metadata. %1 = video width, %2 = video height, %3 = decoder name</extracomment>
-        <translation type="unfinished"></translation>
+        <translation>Відео: %1x%2, %3</translation>
     </message>
     <message>
         <source>Player: %1</source>
-        <translation type="unfinished"></translation>
+        <translation>Гравець: %1</translation>
     </message>
     <message>
         <source>Theme: %1</source>
-        <translation type="unfinished">Тема: %1</translation>
+        <translation>Тема: %1</translation>
     </message>
     <message>
         <source>Map: %1</source>
-        <translation type="unfinished"></translation>
+        <translation>Мапа: %1</translation>
     </message>
     <message>
         <source>Record: %1</source>
-        <translation type="unfinished"></translation>
+        <translation>Рекорд: %1</translation>
     </message>
 </context>
 <context>
@@ -1057,12 +1069,12 @@
     <name>MinesTimeSpinBox</name>
     <message>
         <source>Random</source>
-        <translation type="unfinished"></translation>
+        <translation>Випадково</translation>
     </message>
     <message numerus="yes">
         <source>%1 seconds</source>
-        <translation type="unfinished">
-            <numerusform></numerusform>
+        <translation>
+            <numerusform>%1 секунд</numerusform>
             <numerusform></numerusform>
             <numerusform></numerusform>
         </translation>
@@ -1136,19 +1148,19 @@
     <name>PageCampaign</name>
     <message>
         <source>Team</source>
-        <translation type="unfinished">Команда</translation>
+        <translation>Команда</translation>
     </message>
     <message>
         <source>Campaign</source>
-        <translation type="unfinished"></translation>
+        <translation>Кампанія</translation>
     </message>
     <message>
         <source>Mission</source>
-        <translation type="unfinished"></translation>
+        <translation>Місія</translation>
     </message>
     <message>
         <source>Start fighting</source>
-        <translation type="unfinished">Розпочати бій</translation>
+        <translation>Розпочати бій</translation>
     </message>
 </context>
 <context>
@@ -1170,23 +1182,23 @@
     </message>
     <message>
         <source>Open packages directory</source>
-        <translation type="unfinished"></translation>
+        <translation>Відкрити теку з пакунками</translation>
     </message>
     <message>
         <source>Load the start page</source>
-        <translation type="unfinished"></translation>
+        <translation>Завантажити стартову сторінку</translation>
     </message>
     <message>
         <source>Unknown network error (possibly missing SSL library).</source>
-        <translation type="unfinished"></translation>
+        <translation>Невідома помилка мережі (можливо відсутня бібліотека SSL).</translation>
     </message>
     <message>
         <source>This feature requires an Internet connection, but you don&apos;t appear to be online (error code: %1).</source>
-        <translation type="unfinished"></translation>
+        <translation>Ця функція потребує підключення до Інтернету, але ви, здається, не знаходитесь в мережі (код помилки: %1).</translation>
     </message>
     <message>
         <source>Internal error: Reply object is invalid.</source>
-        <translation type="unfinished"></translation>
+        <translation>Внутрішня помилка: об&apos;єкт відповіді недійсний.</translation>
     </message>
 </context>
 <context>
@@ -1241,11 +1253,11 @@
     </message>
     <message>
         <source>Optimize</source>
-        <translation type="unfinished"></translation>
+        <translation>Оптимізувати</translation>
     </message>
     <message>
         <source>Brush size</source>
-        <translation type="unfinished"></translation>
+        <translation>Розмір пензля</translation>
     </message>
 </context>
 <context>
@@ -1292,44 +1304,44 @@
     </message>
     <message>
         <source>Play a random example of this voice</source>
-        <translation type="unfinished"></translation>
+        <translation>Програти випадковий приклад голосу</translation>
     </message>
     <message>
         <source>Random Hats</source>
-        <translation type="unfinished"></translation>
+        <translation>Випадкові капелюхи</translation>
     </message>
     <message>
         <source>Random Names</source>
-        <translation type="unfinished"></translation>
+        <translation>Випадкові імена</translation>
     </message>
     <message>
         <source>Randomize the team name</source>
-        <translation type="unfinished"></translation>
+        <translation>Випадкова назва команди</translation>
     </message>
     <message>
         <source>Randomize the grave</source>
-        <translation type="unfinished"></translation>
+        <translation>Випадкова могила</translation>
     </message>
     <message>
         <source>Randomize the flag</source>
-        <translation type="unfinished"></translation>
+        <translation>Випадковий прапор</translation>
     </message>
     <message>
         <source>Randomize the voice</source>
-        <translation type="unfinished"></translation>
+        <translation>Випадковий голос</translation>
     </message>
     <message>
         <source>Randomize the fort</source>
-        <translation type="unfinished"></translation>
+        <translation>Випадковий форт</translation>
     </message>
     <message>
         <source>CPU %1</source>
         <extracomment>Name of a flag for computer-controlled enemies. %1 is replaced with the computer level</extracomment>
-        <translation type="unfinished"></translation>
+        <translation>ЦП %1</translation>
     </message>
     <message>
         <source>%1 (%2)</source>
-        <translation type="unfinished"></translation>
+        <translation>%1 (%2)</translation>
     </message>
 </context>
 <context>
@@ -1348,7 +1360,7 @@
     </message>
     <message numerus="yes">
         <source>The best shot award was won by &lt;b&gt;%1&lt;/b&gt; with &lt;b&gt;%2&lt;/b&gt; pts.</source>
-        <translation type="unfinished">
+        <translation>
             <numerusform>Нагороду за кращий постріл отримує &lt;b&gt;%1&lt;/b&gt; з &lt;b&gt;%2&lt;/b&gt; пунктами нанесених втрат.</numerusform>
             <numerusform></numerusform>
             <numerusform></numerusform>
@@ -1438,7 +1450,7 @@
     </message>
     <message>
         <source>With everyone having the same clan color, there was no reason to fight. And so the hedgehogs happily lived in peace ever after.</source>
-        <translation type="unfinished"></translation>
+        <translation>Оскільки клани мали той самий колір, не було причин для бою. Тому їжаки довго жили в мирі і щасті.</translation>
     </message>
 </context>
 <context>
@@ -1515,7 +1527,7 @@
     </message>
     <message>
         <source>Open the Hedgewars online game manual in your web browser</source>
-        <translation type="unfinished"></translation>
+        <translation>Відкрийте онлайн посібник Hedgewars у своєму веб-переглядачі</translation>
     </message>
 </context>
 <context>
@@ -1530,7 +1542,7 @@
     </message>
     <message>
         <source>Start fighting (requires at least 2 teams)</source>
-        <translation type="unfinished"></translation>
+        <translation>Розпочати бій (потребує хоча б 2 команди)</translation>
     </message>
 </context>
 <context>
@@ -1557,19 +1569,19 @@
     </message>
     <message>
         <source>Room name</source>
-        <translation type="unfinished"></translation>
+        <translation>Назва кімнати</translation>
     </message>
     <message>
         <source>Update the room name</source>
-        <translation type="unfinished"></translation>
+        <translation>Оновити назву кімнати</translation>
     </message>
     <message>
         <source>Turn on the lightbulb to show the other players when you&apos;re ready to fight</source>
-        <translation type="unfinished"></translation>
+        <translation>Увімкніть лампочку, щоб показати іншим гравцям, коли будете готові до бою</translation>
     </message>
     <message>
         <source>Start fighting (requires at least 2 teams)</source>
-        <translation type="unfinished"></translation>
+        <translation>Розпочати бій (потребує хоча б 2 команди)</translation>
     </message>
 </context>
 <context>
@@ -1756,7 +1768,7 @@
     <message>
         <source>x</source>
         <extracomment>Multiplication sign, to be used between two numbers. Note the “x” is only a dummy character, we recommend to use “×” if your language permits it</extracomment>
-        <translation type="unfinished"></translation>
+        <translation>x</translation>
     </message>
     <message>
         <source>MISSING LANGUAGE NAME [%1]</source>
@@ -1764,15 +1776,15 @@
     </message>
     <message>
         <source>Check now</source>
-        <translation type="unfinished"></translation>
+        <translation>Перевірити зараз</translation>
     </message>
     <message>
         <source>Can&apos;t delete last team</source>
-        <translation type="unfinished"></translation>
+        <translation>Неможливо видалити останню команду</translation>
     </message>
     <message>
         <source>You can&apos;t delete the last team!</source>
-        <translation type="unfinished"></translation>
+        <translation>Ви не можете видалити останню команду!</translation>
     </message>
 </context>
 <context>
@@ -1787,15 +1799,15 @@
     </message>
     <message>
         <source>Play demo</source>
-        <translation type="unfinished">Грати демо</translation>
+        <translation>Грати демо</translation>
     </message>
     <message>
         <source>Play the selected demo</source>
-        <translation type="unfinished"></translation>
+        <translation>Грати обране демо</translation>
     </message>
     <message>
         <source>Load the selected game</source>
-        <translation type="unfinished"></translation>
+        <translation>Завантажити обрану гру</translation>
     </message>
 </context>
 <context>
@@ -2001,7 +2013,7 @@
     </message>
     <message>
         <source>Each clan starts in its own part of the terrain.</source>
-        <translation type="unfinished"></translation>
+        <translation>Кожен клан стартує на своїй території.</translation>
     </message>
     <message>
         <source>Overall damage and knockback in percent</source>
@@ -2013,7 +2025,7 @@
     </message>
     <message>
         <source>Initial health of hedgehogs</source>
-        <translation type="unfinished"></translation>
+        <translation>Початкове здоров&apos;я їжаків</translation>
     </message>
     <message>
         <source>How many rounds have to be played before Sudden Death begins</source>
@@ -2029,7 +2041,7 @@
     </message>
     <message>
         <source>Maximum rope length in percent</source>
-        <translation type="unfinished"></translation>
+        <translation>Максимальна довжина мотузки у відсотках</translation>
     </message>
     <message>
         <source>Likelihood of a dropped crate being a health crate. All other crates will be weapon or utility crates.</source>
@@ -2041,7 +2053,7 @@
     </message>
     <message>
         <source>Health bonus for collecting a health crate</source>
-        <translation type="unfinished"></translation>
+        <translation>Бонус здоров&apos;я за підібраний ящик зі здоров&apos;ям</translation>
     </message>
     <message>
         <source>Detonation timer of mines. The random timer lies between 0 and 5 seconds. The timer of air mines will be a quarter of the mines timer.</source>
@@ -2069,7 +2081,7 @@
     </message>
     <message>
         <source>Time you get after an attack</source>
-        <translation type="unfinished"></translation>
+        <translation>Час, який у вас є після атаки</translation>
     </message>
     <message>
         <source>Additional parameter to configure game styles. The meaning depends on the used style, refer to the documentation. When in doubt, leave it empty.</source>
@@ -2077,19 +2089,19 @@
     </message>
     <message>
         <source>Name of this scheme</source>
-        <translation type="unfinished"></translation>
+        <translation>Назва цієї схеми</translation>
     </message>
     <message>
         <source>Select a hedgehog at the beginning of a turn</source>
-        <translation type="unfinished"></translation>
+        <translation>Виберіть їжака на початку ходу</translation>
     </message>
     <message>
         <source>Land can not be destroyed by most weapons.</source>
-        <translation type="unfinished"></translation>
+        <translation>Земля не може бути знищена більшістю зброї.</translation>
     </message>
     <message>
         <source>%1 (%2)</source>
-        <translation type="unfinished"></translation>
+        <translation>%1 (%2)</translation>
     </message>
 </context>
 <context>
@@ -2158,27 +2170,27 @@
     </message>
     <message>
         <source>Pick the training to play</source>
-        <translation type="unfinished"></translation>
+        <translation>Виберіть навчальну гру</translation>
     </message>
     <message>
         <source>Pick the challenge to play</source>
-        <translation type="unfinished"></translation>
+        <translation>Виберіть виклик</translation>
     </message>
     <message>
         <source>Pick the scenario to play</source>
-        <translation type="unfinished"></translation>
+        <translation>Виберіть сценарій гри</translation>
     </message>
     <message>
         <source>Trainings</source>
-        <translation type="unfinished"></translation>
+        <translation>Навчання</translation>
     </message>
     <message>
         <source>Challenges</source>
-        <translation type="unfinished"></translation>
+        <translation>Виклики</translation>
     </message>
     <message>
         <source>Scenarios</source>
-        <translation type="unfinished"></translation>
+        <translation>Сценарії</translation>
     </message>
 </context>
 <context>
@@ -2195,8 +2207,8 @@
         <source>%1 bytes</source>
         <translation>
             <numerusform>%1 байт</numerusform>
-            <numerusform></numerusform>
-            <numerusform></numerusform>
+            <numerusform>%1 байти</numerusform>
+            <numerusform>%1 байтів</numerusform>
         </translation>
     </message>
     <message>
@@ -2222,12 +2234,12 @@
     <message>
         <source>%1%</source>
         <extracomment>Video encoding progress. %1 = number</extracomment>
-        <translation type="unfinished"></translation>
+        <translation>%1%</translation>
     </message>
     <message>
         <source>%1 (%2%) - %3</source>
         <extracomment>Video encoding list entry. %1 = file name, %2 = percent complete, %3 = video operation type (e.g. “encoding”)</extracomment>
-        <translation type="unfinished"></translation>
+        <translation>%1 (%2%) - %3</translation>
     </message>
 </context>
 <context>
@@ -2290,15 +2302,15 @@
     </message>
     <message>
         <source>Show password protected</source>
-        <translation type="unfinished"></translation>
+        <translation>Показати захищені паролем</translation>
     </message>
     <message>
         <source>Show join restricted</source>
-        <translation type="unfinished"></translation>
+        <translation>Показати з обмеженим приєднанням</translation>
     </message>
     <message>
         <source>Delegate room control</source>
-        <translation type="unfinished"></translation>
+        <translation>Делегувати керування кімнатою</translation>
     </message>
 </context>
 <context>
@@ -2409,20 +2421,20 @@
     </message>
     <message>
         <source>Enable visual effects such as animated menu transitions and falling stars</source>
-        <translation type="unfinished"></translation>
+        <translation>Ввімкнути візуальні ефекти, такі як анімаційні переходи меню та падіння зірок</translation>
     </message>
     <message>
         <source>If enabled, Hedgewars adds the date and time in the form &quot;YYYY-MM-DD_hh-mm&quot; for automatically created demos.</source>
-        <translation type="unfinished"></translation>
+        <translation>Якщо ввімкнено, Hedgewars додасть дату та час у вигляді &quot;YYYY-MM-DD_hh-mm&quot; до автоматично створених демо.</translation>
     </message>
     <message>
         <source>Dampen when losing focus</source>
         <extracomment>Checkbox text. If checked, the in-game audio volume is reduced (=dampened) when the game window loses its focus</extracomment>
-        <translation type="unfinished"></translation>
+        <translation>Занижувати звук при втраті фокусу</translation>
     </message>
     <message>
         <source>Reduce the game audio volume if the game window has lost its focus</source>
-        <translation type="unfinished"></translation>
+        <translation>Знизити гучність звук гри, якщо вікно гри втратило фокус</translation>
     </message>
 </context>
 <context>
@@ -2517,31 +2529,31 @@
     </message>
     <message>
         <source>Computer (Level %1)</source>
-        <translation type="unfinished"></translation>
+        <translation>Комп&apos;ютер (Рівень %1)</translation>
     </message>
     <message>
         <source>Stereoscopy creates an illusion of depth when you wear 3D glasses.</source>
-        <translation type="unfinished"></translation>
+        <translation>Стереоскопія створює ілюзію глибини, коли ви одягаєте 3D-окуляри.</translation>
     </message>
     <message>
         <source>24 FPS</source>
-        <translation type="unfinished"></translation>
+        <translation>24 FPS</translation>
     </message>
     <message>
         <source>25 FPS</source>
-        <translation type="unfinished"></translation>
+        <translation>25 FPS</translation>
     </message>
     <message>
         <source>30 FPS</source>
-        <translation type="unfinished"></translation>
+        <translation>30 FPS</translation>
     </message>
     <message>
         <source>50 FPS</source>
-        <translation type="unfinished"></translation>
+        <translation>50 FPS</translation>
     </message>
     <message>
         <source>60 FPS</source>
-        <translation type="unfinished"></translation>
+        <translation>60 FPS</translation>
     </message>
 </context>
 <context>
@@ -2851,15 +2863,15 @@
     </message>
     <message>
         <source>Air Mines</source>
-        <translation type="unfinished"></translation>
+        <translation>Повітряні міни</translation>
     </message>
     <message>
         <source>Player</source>
-        <translation type="unfinished"></translation>
+        <translation>Гравець</translation>
     </message>
     <message>
         <source>Barrels</source>
-        <translation type="unfinished"></translation>
+        <translation>Бочки</translation>
     </message>
     <message>
         <source>% Retreat Time</source>
@@ -2867,12 +2879,12 @@
     </message>
     <message>
         <source>Stereoscopy</source>
-        <translation type="unfinished"></translation>
+        <translation>Стереоскопія</translation>
     </message>
     <message>
         <source>Bitrate (Kibit/s)</source>
         <extracomment>“Kibit/s” is the symbol for 1024 bits per second</extracomment>
-        <translation type="unfinished"></translation>
+        <translation>Бітрейт (Kibit/s)</translation>
     </message>
     <message>
         <source>Loading&lt;br&gt;CAPTCHA ...</source>
@@ -2895,11 +2907,11 @@
     </message>
     <message>
         <source>unnamed (%1)</source>
-        <translation type="unfinished"></translation>
+        <translation>без_назви (%1)</translation>
     </message>
     <message>
         <source>Hedgehog %1</source>
-        <translation type="unfinished"></translation>
+        <translation>Їжак %1</translation>
     </message>
 </context>
 <context>
@@ -3137,53 +3149,55 @@
     </message>
     <message>
         <source>Teams - Name already taken</source>
-        <translation type="unfinished"></translation>
+        <translation>Команди - Назва вже зайнята</translation>
     </message>
     <message>
         <source>The team name &apos;%1&apos; is already taken, so your team has been renamed to &apos;%2&apos;.</source>
-        <translation type="unfinished"></translation>
+        <translation>Назва команди &apos;%1&apos; вже зайнята, тому ваша команда була перейменована на &apos;%2&apos;.</translation>
     </message>
     <message>
         <source>Please select a file from the list.</source>
-        <translation type="unfinished"></translation>
+        <translation>Виберіть файл зі списку.</translation>
     </message>
     <message>
         <source>Cannot rename file to %1.</source>
-        <translation type="unfinished"></translation>
+        <translation>Неможливо перейменувати файл %1.</translation>
     </message>
     <message>
         <source>Cannot delete file %1.</source>
-        <translation type="unfinished"></translation>
+        <translation>Неможливо видалити файл %1.</translation>
     </message>
     <message>
         <source>Welcome to Hedgewars</source>
-        <translation type="unfinished"></translation>
+        <translation>Вітаємо в Hedgewars</translation>
     </message>
     <message>
         <source>Welcome to Hedgewars!
 
 You seem to be new around here. Would you like to play some training missions first to learn the basics of Hedgewars?</source>
-        <translation type="unfinished"></translation>
+        <translation>Вітаємо в Hedgewars!
+
+Ви, схоже, новенький. Чи не хочете спочатку зіграти деякі навчальні місії, щоб вивчити основи Hedgewars?</translation>
     </message>
     <message>
         <source>Cannot use the weapon scheme &apos;%1&apos;!</source>
-        <translation type="unfinished"></translation>
+        <translation>Неможливо використати схему зброї &apos;%1&apos;!</translation>
     </message>
     <message>
         <source>The connection to the server is lost.</source>
-        <translation type="unfinished"></translation>
+        <translation>З&apos;єднання з сервером втрачено.</translation>
     </message>
     <message>
         <source>Schemes - Name already taken</source>
-        <translation type="unfinished"></translation>
+        <translation>Схеми - Назва вже зайнята</translation>
     </message>
     <message>
         <source>A scheme with the name &apos;%1&apos; already exists. Your scheme has been renamed to &apos;%2&apos;.</source>
-        <translation type="unfinished"></translation>
+        <translation>Схема з назвою &apos;%1&apos; вже існує. Ваша схема перейменована на &apos;%2&apos;.</translation>
     </message>
     <message>
         <source>A weapon scheme with the name &apos;%1&apos; already exists. Changes made to the weapon scheme have been discarded.</source>
-        <translation type="unfinished"></translation>
+        <translation>Схема зброї з назвою &apos;%1&apos; вже існує. Зміни, внесені до схеми зброї, були відхилені.</translation>
     </message>
 </context>
 <context>
@@ -3320,7 +3334,7 @@
     <name>QSpinBox</name>
     <message>
         <source>Specify the bitrate of recorded videos as a multiple of 1024 bits per second</source>
-        <translation type="unfinished"></translation>
+        <translation>Вкажіть бітрейт записаного відео кратний 1024 бітам за секунду</translation>
     </message>
 </context>
 <context>
@@ -3400,7 +3414,7 @@
     </message>
     <message>
         <source>Forts</source>
-        <translation type="unfinished"></translation>
+        <translation>Форти</translation>
     </message>
 </context>
 <context>
@@ -3424,7 +3438,7 @@
     <message>
         <source>Seed</source>
         <extracomment>Refers to the &quot;random seed&quot;; the source of randomness in the game</extracomment>
-        <translation type="unfinished">Висів</translation>
+        <translation>Висів</translation>
     </message>
 </context>
 <context>
@@ -3455,19 +3469,19 @@
     </message>
     <message>
         <source>New</source>
-        <translation type="unfinished">Нова</translation>
+        <translation>Новий</translation>
     </message>
     <message>
         <source>New (%1)</source>
-        <translation type="unfinished"></translation>
+        <translation>Новий (%1)</translation>
     </message>
     <message>
         <source>Copy of %1</source>
-        <translation type="unfinished"></translation>
+        <translation>Копія %1</translation>
     </message>
     <message>
         <source>Copy of %1 (%2)</source>
-        <translation type="unfinished"></translation>
+        <translation>Копія %1 (%2)</translation>
     </message>
 </context>
 <context>
@@ -3489,7 +3503,12 @@
 We are very sorry for the inconvenience :(
 
 If this keeps happening, please click the &apos;%2&apos; button in the main menu!</source>
-        <translation type="unfinished"></translation>
+        <translation>Ігровий двигун несподівано помер!
+(код виходу %1)
+
+Нам дуже шкода за незручності :(
+
+Якщо це триватиме, натисніть на кнопку &apos;%2&apos; в головному меню!</translation>
     </message>
 </context>
 <context>
@@ -3515,7 +3534,7 @@
     </message>
     <message>
         <source>Choose a theme</source>
-        <translation type="unfinished"></translation>
+        <translation>Виберіть тему</translation>
     </message>
 </context>
 <context>
@@ -3860,7 +3879,7 @@
     </message>
     <message>
         <source>Delete</source>
-        <translation>Видалити</translation>
+        <translation>Delete</translation>
     </message>
     <message>
         <source>Mouse: Left button</source>
@@ -3896,15 +3915,15 @@
     </message>
     <message>
         <source>Return</source>
-        <translation type="unfinished"></translation>
+        <translation>Return</translation>
     </message>
     <message>
         <source>Pause</source>
-        <translation type="unfinished"></translation>
+        <translation>Pause</translation>
     </message>
     <message>
         <source>Escape</source>
-        <translation type="unfinished"></translation>
+        <translation>Escape</translation>
     </message>
     <message>
         <source>Space</source>
@@ -3972,11 +3991,11 @@
     </message>
     <message>
         <source>Enter</source>
-        <translation type="unfinished"></translation>
+        <translation>Enter</translation>
     </message>
     <message>
         <source>Equals</source>
-        <translation type="unfinished"></translation>
+        <translation>Дорівнює</translation>
     </message>
     <message>
         <source>Up</source>
@@ -3996,23 +4015,23 @@
     </message>
     <message>
         <source>Insert</source>
-        <translation type="unfinished"></translation>
+        <translation>Insert</translation>
     </message>
     <message>
         <source>Home</source>
-        <translation type="unfinished"></translation>
+        <translation>Home</translation>
     </message>
     <message>
         <source>End</source>
-        <translation type="unfinished"></translation>
+        <translation>End</translation>
     </message>
     <message>
         <source>Page up</source>
-        <translation type="unfinished"></translation>
+        <translation>Page up</translation>
     </message>
     <message>
         <source>Page down</source>
-        <translation type="unfinished"></translation>
+        <translation>Page down</translation>
     </message>
     <message>
         <source>Num lock</source>
@@ -4020,11 +4039,11 @@
     </message>
     <message>
         <source>Caps lock</source>
-        <translation type="unfinished"></translation>
+        <translation>Caps lock</translation>
     </message>
     <message>
         <source>Scroll lock</source>
-        <translation type="unfinished"></translation>
+        <translation>Scroll lock</translation>
     </message>
     <message>
         <source>Right shift</source>
@@ -4052,27 +4071,27 @@
     </message>
     <message>
         <source>Right meta</source>
-        <translation type="unfinished"></translation>
+        <translation>Права Meta</translation>
     </message>
     <message>
         <source>Left meta</source>
-        <translation type="unfinished"></translation>
+        <translation>Ліва Meta</translation>
     </message>
     <message>
         <source>A button</source>
-        <translation type="unfinished"></translation>
+        <translation>Кнопка A</translation>
     </message>
     <message>
         <source>B button</source>
-        <translation type="unfinished"></translation>
+        <translation>Кнопка B</translation>
     </message>
     <message>
         <source>X button</source>
-        <translation type="unfinished"></translation>
+        <translation>Кнопка X</translation>
     </message>
     <message>
         <source>Y button</source>
-        <translation type="unfinished"></translation>
+        <translation>Кнопка Y</translation>
     </message>
     <message>
         <source>LB button</source>
@@ -4282,19 +4301,19 @@
     </message>
     <message>
         <source>New voting started</source>
-        <translation type="unfinished"></translation>
+        <translation>Почалося нове голосування</translation>
     </message>
     <message>
         <source>kick</source>
-        <translation type="unfinished"></translation>
+        <translation>копнути</translation>
     </message>
     <message>
         <source>map</source>
-        <translation type="unfinished"></translation>
+        <translation>мапа</translation>
     </message>
     <message>
         <source>pause</source>
-        <translation type="unfinished">пауза</translation>
+        <translation>пауза</translation>
     </message>
     <message>
         <source>Reconnected too fast</source>
@@ -4318,7 +4337,7 @@
     </message>
     <message>
         <source>new seed</source>
-        <translation type="unfinished"></translation>
+        <translation>новий висів</translation>
     </message>
     <message>
         <source>/maxteams: specify number from 2 to 8</source>
@@ -4338,11 +4357,11 @@
     </message>
     <message>
         <source>Access denied.</source>
-        <translation type="unfinished"></translation>
+        <translation>Доступ заборонено.</translation>
     </message>
     <message>
         <source>You&apos;re not the room master!</source>
-        <translation type="unfinished"></translation>
+        <translation>Ви не голова кімнати!</translation>
     </message>
     <message>
         <source>Corrupted hedgehogs info!</source>
@@ -4350,15 +4369,15 @@
     </message>
     <message>
         <source>Too many teams!</source>
-        <translation type="unfinished"></translation>
+        <translation>Забагато команд!</translation>
     </message>
     <message>
         <source>Too many hedgehogs!</source>
-        <translation type="unfinished"></translation>
+        <translation>Забагато їжаків!</translation>
     </message>
     <message>
         <source>There&apos;s already a team with same name in the list.</source>
-        <translation type="unfinished"></translation>
+        <translation>Команда з таким же іменем вже є в списку.</translation>
     </message>
     <message>
         <source>Joining not possible: Round is in progress.</source>
@@ -4410,7 +4429,7 @@
     </message>
     <message>
         <source>No such room.</source>
-        <translation type="unfinished"></translation>
+        <translation>Немає такої кімнати.</translation>
     </message>
     <message>
         <source>Room version incompatible to your Hedgewars version!</source>
@@ -4442,7 +4461,7 @@
     </message>
     <message>
         <source>Bad number.</source>
-        <translation type="unfinished"></translation>
+        <translation>Невірне число.</translation>
     </message>
     <message>
         <source>There&apos;s no voting going on.</source>
@@ -4450,15 +4469,15 @@
     </message>
     <message>
         <source>You already have voted.</source>
-        <translation type="unfinished"></translation>
+        <translation>Ви вже проголосували.</translation>
     </message>
     <message>
         <source>Your vote has been counted.</source>
-        <translation type="unfinished"></translation>
+        <translation>Ваш голос було враховано.</translation>
     </message>
     <message>
         <source>Voting closed.</source>
-        <translation type="unfinished"></translation>
+        <translation>Голосування завершене.</translation>
     </message>
     <message>
         <source>Pause toggled.</source>
@@ -4466,11 +4485,11 @@
     </message>
     <message>
         <source>Voting expired.</source>
-        <translation type="unfinished"></translation>
+        <translation>Голосування вже скінчилось.</translation>
     </message>
     <message>
         <source>hedgehogs per team: </source>
-        <translation type="unfinished"></translation>
+        <translation>їжаків в команді: </translation>
     </message>
     <message>
         <source>/info &lt;player&gt;: Show info about player</source>
@@ -4554,11 +4573,11 @@
     </message>
     <message>
         <source>room</source>
-        <translation type="unfinished"></translation>
+        <translation>кімната</translation>
     </message>
     <message>
         <source>lobby</source>
-        <translation type="unfinished"></translation>
+        <translation>вестибюль</translation>
     </message>
     <message>
         <source>(playing)</source>
@@ -4582,7 +4601,7 @@
     </message>
     <message>
         <source>Kicked</source>
-        <translation type="unfinished"></translation>
+        <translation>Копнутий</translation>
     </message>
     <message>
         <source>This server only allows registered users to join.</source>
@@ -4626,7 +4645,7 @@
     </message>
     <message>
         <source>Super power activated.</source>
-        <translation type="unfinished"></translation>
+        <translation>Суперсила активована.</translation>
     </message>
     <message>
         <source>Unknown command or invalid parameters. Say &apos;/help&apos; in chat for a list of commands.</source>
@@ -4634,7 +4653,7 @@
     </message>
     <message>
         <source>You can&apos;t kick yourself!</source>
-        <translation type="unfinished"></translation>
+        <translation>Не можна копати себе!</translation>
     </message>
     <message>
         <source>You can&apos;t kick the only other player!</source>
@@ -4654,7 +4673,7 @@
     </message>
     <message>
         <source>You&apos;re already the room master.</source>
-        <translation type="unfinished"></translation>
+        <translation>Ви вже є головою кімнати!</translation>
     </message>
     <message>
         <source>Greeting message cleared.</source>
@@ -4674,11 +4693,11 @@
     </message>
     <message>
         <source>You&apos;re the new room master!</source>
-        <translation type="unfinished"></translation>
+        <translation>Ви новий голова кімнати!</translation>
     </message>
     <message>
         <source>/quit: Quit the server</source>
-        <translation type="unfinished"></translation>
+        <translation>/quit: Вийти з сервера</translation>
     </message>
     <message>
         <source>This command is only available in the lobby.</source>
@@ -4686,7 +4705,7 @@
     </message>
     <message>
         <source>This command is only available in rooms.</source>
-        <translation type="unfinished"></translation>
+        <translation>Ця команда працює лише в кімнатах.</translation>
     </message>
 </context>
 </TS>
--- a/share/hedgewars/Data/Locale/uk.lua	Fri Nov 09 14:12:00 2018 +0300
+++ b/share/hedgewars/Data/Locale/uk.lua	Fri Nov 09 14:15:22 2018 +0300
@@ -1,32 +1,32 @@
 locale = {
 --      ["..."] = "",
---      ["011101000"] = "", -- A_Classic_Fairytale:dragon
---      ["011101001"] = "", -- A_Classic_Fairytale:backstab, A_Classic_Fairytale:dragon, A_Classic_Fairytale:enemy, A_Classic_Fairytale:family, A_Classic_Fairytale:journey, A_Classic_Fairytale:queen, A_Classic_Fairytale:shadow, A_Classic_Fairytale:united
+--      ["011101000"] = "011101000", -- A_Classic_Fairytale:dragon
+--      ["011101001"] = "011101001", -- A_Classic_Fairytale:backstab, A_Classic_Fairytale:dragon, A_Classic_Fairytale:enemy, A_Classic_Fairytale:family, A_Classic_Fairytale:journey, A_Classic_Fairytale:queen, A_Classic_Fairytale:shadow, A_Classic_Fairytale:united
 --      ["10 weapon schemes"] = "", -- Continental_supplies
 --      ["15+%d damage, %d invulnerable left"] = "", -- Continental_supplies
 --      ["1-5, Precise + 1-4: Choose structure type"] = "", -- Construction_Mode
---      ["+1 barrel!"] = "", -- Tumbler
+--      ["+1 barrel!"] = "+1 бочка!", -- Tumbler
 --      ["%.1f seconds were remaining."] = "", -- Basic_Training_-_Bazooka
---      ["%.1fs"] = "", -- Racer, TechRacer
+--      ["%.1fs"] = "%.1fс", -- Racer, TechRacer
 --      ["+1 Grenade"] = "", -- Basic_Training_-_Flying_Saucer
---      ["+1 mine!"] = "", -- Tumbler
---      ["+1 point"] = "", -- Mutant
---      ["-1 point"] = "", -- Mutant
---      ["-1 to anyone for a suicide"] = "", -- Mutant
+--      ["+1 mine!"] = "+1 міна!", -- Tumbler
+--      ["+1 point"] = "+1 очко", -- Mutant
+--      ["-1 point"] = "-1 очко", -- Mutant
+--      ["-1 to anyone for a suicide"] = "-1 кожному за суїцид", -- Mutant
 --      ["+1 to the Bottom Feeder for killing anyone"] = "", -- Mutant
---      ["+1 to the Mutant for killing anyone"] = "", -- Mutant
---      ["+2 for becoming the Mutant"] = "", -- Mutant
---      ["30 minutes later..."] = "", -- A_Classic_Fairytale:shadow
---      ["%.3fs"] = "", -- A_Space_Adventure:ice02
+--      ["+1 to the Mutant for killing anyone"] = "+1 Мутанту за вбивство будь-кого", -- Mutant
+--      ["+2 for becoming the Mutant"] = "+2 за те що став Мутантом", -- Mutant
+--      ["30 minutes later..."] = "За 30 хвилин...", -- A_Classic_Fairytale:shadow
+--      ["%.3fs"] = "%.3fс", -- A_Space_Adventure:ice02
 --      ["5 additional enemies will be spawned during the game."] = "", -- A_Space_Adventure:fruit01
 --      ["5 Deadly Hogs"] = "", -- A_Space_Adventure:death02
 --      ["6 more seconds added to the clock"] = "", -- A_Space_Adventure:ice02
 --      ["About a month ago, a cyborg came and told us that you're the cannibals!"] = "", -- A_Classic_Fairytale:enemy
 --      ["Above-average pilot"] = "", -- User_Mission_-_RCPlane_Challenge
---      ["Accuracy Bonus! +15 points"] = "", -- Space_Invasion
---      ["Accuracy bonus: +%d points"] = "", -- Basic_Training_-_Sniper_Rifle
+--      ["Accuracy Bonus! +15 points"] = "Бонус Точності! +15 очок", -- Space_Invasion
+--      ["Accuracy bonus: +%d points"] = "Бонус точності: +%d очок", -- Basic_Training_-_Sniper_Rifle
 --      ["Ace"] = "", -- User_Mission_-_RCPlane_Challenge, User_Mission_-_Rope_Knock_Challenge
---      ["Achievement gotten: %s"] = "", -- User_Mission_-_RCPlane_Challenge, User_Mission_-_That_Sinking_Feeling, User_Mission_-_Bamboo_Thicket, User_Mission_-_Dangerous_Ducklings, Basic_Training_-_Rope, Tumbler
+--      ["Achievement gotten: %s"] = "Досягнення: %s", -- User_Mission_-_RCPlane_Challenge, User_Mission_-_That_Sinking_Feeling, User_Mission_-_Bamboo_Thicket, User_Mission_-_Dangerous_Ducklings, Basic_Training_-_Rope, Tumbler
         ["A Classic Fairytale"] = "Класична казка", -- A_Classic_Fairytale:first_blood
 --      ["A crate critical to this mission has been destroyed."] = "", -- SimpleMission
 --      ["Actually, you aren't worthy of life! Take this..."] = "", -- A_Classic_Fairytale:shadow
@@ -52,7 +52,7 @@
 --      ["Aiming practice"] = "", -- TargetPractice
         ["Aiming Practice"] = "Практика прицілювання", --Bazooka, Shotgun, SniperRifle
 --      ["Aim: [Up]/[Down]"] = "", -- Basic_Training_-_Bazooka, Basic_Training_-_Grenade, Basic_Training_-_Rope
---      ["Air Attack"] = "", -- Construction_Mode
+--      ["Air Attack"] = "Повітряна атака", -- Construction_Mode
 --      ["Air General"] = "", -- Battalion
 --      ["Air Mine Placement Mode"] = "", -- HedgeEditor
 --      ["AIR MINE PLACEMENT MODE"] = "", -- HedgeEditor
@@ -79,10 +79,10 @@
 --      ["Always being considered weak and fragile."] = "", -- A_Classic_Fairytale:queen
 --      ["Amazing! I was never beaten in a race before!"] = "", -- A_Space_Adventure:moon02
 --      ["Ammo depleted!"] = "", -- Space_Invasion
---      ["Ammo: %d"] = "", -- Tumbler
+--      ["Ammo: %d"] = "Боєприпаси: %d", -- Tumbler
         ["Ammo is reset at the end of your turn."] = "Боєприпаси обнуляються в кінці вашого ходу.",
 --      ["Ammo Limit: Hogs can’t have more than 1 ammo per type"] = "", -- Highlander
---      ["Ammo Maniac! +5 points!"] = "", -- Space_Invasion
+--      ["Ammo Maniac! +5 points!"] = "Маніяк Боєприпасів! +5 очок!", -- Space_Invasion
 --      ["A mysterious Box"] = "", -- Basic_Training_-_Movement
         ["And how am I alive?!"] = "І чому я живий!?", -- A_Classic_Fairytale:enemy
 --      ["And I just forgot the checkpoint of my main mission. Great, just great!"] = "", -- A_Space_Adventure:cosmos
@@ -165,7 +165,7 @@
 --      ["Back Jumping (2/2)"] = "", -- Basic_Training_-_Movement
 --      ["Backstab"] = "", -- A_Classic_Fairytale:backstab
 --      ["Bacon"] = "", -- 
---      ["Bad Guy"] = "", -- User_Mission_-_The_Great_Escape
+--      ["Bad Guy"] = "Поганий хлопець", -- User_Mission_-_The_Great_Escape
 --      ["Badmad"] = "", -- portal
         ["Bad Team"] = "Погана команда", -- User_Mission_-_The_Great_Escape
 --      ["Bad timing"] = "", -- A_Space_Adventure:fruit01
@@ -187,7 +187,7 @@
 --      ["Basic Movement Training"] = "", -- Basic_Training_-_Movement
 --      ["Basic Rope Training"] = "", -- Basic_Training_-_Rope
 --      ["Basic Training"] = "", -- Basic_Training_-_Bazooka, Basic_Training_-_Grenade, Basic_Training_-_Movement, Basic_Training_-_Rope
---      ["Basketball"] = "", -- Basketball
+--      ["Basketball"] = "Баскетбол", -- Basketball
         ["Bat balls at your enemies and|push them into the sea!"] = "Закидайте ворогів м'ячами щоб|зіштовути їх у море!",
 --      ["Battalion"] = "", -- Battalion
 --      ["Battle Starts Now!"] = "", -- A_Space_Adventure:fruit01
@@ -208,7 +208,7 @@
 --      ["Below-average pilot"] = "", -- User_Mission_-_RCPlane_Challenge
 --      ["Besides, why would I choose certain death?"] = "", -- A_Classic_Fairytale:queen
         ["Best laps per team: "] = "Кращі партії на команду: ",
---      ["Best team times: "] = "", -- Racer, TechRacer
+--      ["Best team times: "] = "Кращий командний час: ", -- Racer, TechRacer
 --      ["Better get yourself another health crate to heal your wounds."] = "", -- Basic_Training_-_Movement
 --      ["Better luck next time!"] = "", -- ClimbHome
 --      ["Better Safe Than Sorry"] = "", -- A_Space_Adventure:desert02
@@ -226,13 +226,13 @@
 --      ["Biomechanic Team"] = "", -- A_Classic_Fairytale:family
 --      ["Bitter"] = "", -- 
 --      ["Blanka"] = "", -- 
---      ["Blender"] = "", -- A_Classic_Fairytale:family
+--      ["Blender"] = "Блендер", -- A_Classic_Fairytale:family
 --      ["Bloodpie"] = "", -- A_Classic_Fairytale:backstab
 --      ["Bloodrocutor"] = "", -- A_Classic_Fairytale:shadow
 --      ["Bloodsucker"] = "", -- A_Classic_Fairytale:shadow
         ["Bloody Rookies"] = "Криваві Салаги", -- 01#Boot_Camp, User_Mission_-_Dangerous_Ducklings, User_Mission_-_Diver, User_Mission_-_Spooky_Tree
 --      ["Blue"] = "", -- 
---      ["Blue Team"] = "", -- User_Mission_-_Dangerous_Ducklings
+--      ["Blue Team"] = "Блакитна команда", -- User_Mission_-_Dangerous_Ducklings
 --      ["Bob"] = "", -- A_Space_Adventure:cosmos
 --      ["Bobo"] = "", -- User_Mission_-_Nobody_Laugh
 --      ["Bone Jackson"] = "", -- A_Classic_Fairytale:backstab
@@ -243,8 +243,8 @@
 --      ["BOOM! %s really didn't like the invaders, so they decided to destroy as much as %d of them."] = "", -- Space_Invasion
         ["Boom!"] = "Бабах!",
 --      ["Boris"] = "", -- A_Space_Adventure:moon01
---      ["Boss defeated! +30 points!"] = "", -- Space_Invasion
---      ["Boss Slayer! +25 points!"] = "", -- Space_Invasion
+--      ["Boss defeated! +30 points!"] = "Боса переможено! +30 очок!", -- Space_Invasion
+--      ["Boss Slayer! +25 points!"] = "Вбивця Боса! +25 очок!", -- Space_Invasion
 --      ["Both Barrels"] = "", -- 
 --      ["Both your hedgehogs must survive."] = "", -- User_Mission_-_Teamwork_2, User_Mission_-_Teamwork
 --      ["Bottom Feeder"] = "", -- Mutant
@@ -299,11 +299,11 @@
 --      ["Cannibal Sentry"] = "", -- A_Classic_Fairytale:journey
         ["Cannibals?! You're the cannibals!"] = "Канібали!? Ви канібали!", -- A_Classic_Fairytale:enemy
         ["Cannibals"] = "Канібали", -- A_Classic_Fairytale:enemy, A_Classic_Fairytale:epil, A_Classic_Fairytale:first_blood
---      ["Can you do it?"] = "", -- A_Space_Adventure:ice02
+--      ["Can you do it?"] = "Ти можеш це зробити?", -- A_Space_Adventure:ice02
 --      ["Cappy"] = "", -- Basic_Training_-_Movement
 --      ["Captain Lime"] = "", -- A_Space_Adventure:fruit01, A_Space_Adventure:fruit02
 --      ["Captain Lime offered his help if you assist him in battle."] = "", -- A_Space_Adventure:fruit01
---      ["Capture The Flag"] = "", -- Capture_the_Flag, CTF_Blizzard
+--      ["Capture The Flag"] = "Захоплення прапора", -- Capture_the_Flag, CTF_Blizzard
 --      ["Careful, hedgehogs can't swim!"] = "", -- Basic_Training_-_Movement
         ["Careless"] = "Безтурботний",
 --      ["Carol"] = "", -- A_Classic_Fairytale:family
@@ -323,7 +323,7 @@
 --      ["Change Sprite Frame: [Precise]+[Left], [Precise]+[Right]"] = "", -- HedgeEditor
 --      ["Change Sprite: [Left], [Right]"] = "", -- HedgeEditor
 --      ["Change Timer: [Left], [Right]"] = "", -- HedgeEditor
---      ["Change weapon: [Long jump] or [Slot 1]-[Slot 3]"] = "", -- Tumbler
+--      ["Change weapon: [Long jump] or [Slot 1]-[Slot 3]"] = "Змінити Зброю: [Довгий стрибок] або [Слот 1]-[Слот 3]", -- Tumbler
 --      ["Charmander"] = "", -- 
 --      ["Chasing the blue hog"] = "", -- A_Space_Adventure:moon02
 --      ["Cheater"] = "", -- User_Mission_-_RCPlane_Challenge
@@ -375,10 +375,10 @@
         ["Complete the track as fast as you can!"] = "Подолайте трасу так швидко, як тільки зможете!",
 --      ["Completion time: %.2fs"] = "", -- User_Mission_-_Rope_Knock_Challenge
 --      ["Comrades! Sail me away!"] = "", -- A_Classic_Fairytale:queen
---      ["Configuration accepted."] = "", -- WxW
---      ["Configuration phase"] = "", -- WxW
---      ["Congrats! You won!"] = "", -- A_Space_Adventure:moon01
---      ["Congratulations"] = "", -- Basic_Training_-_Rope
+--      ["Configuration accepted."] = "Привітання прийняті.", -- WxW
+--      ["Configuration phase"] = "Привітальна фраза", -- WxW
+--      ["Congrats! You won!"] = "Вітання! Ви перемогли!", -- A_Space_Adventure:moon01
+--      ["Congratulations"] = "Вітання", -- Basic_Training_-_Rope
 --      ["Congratulations, you acquired the device part!"] = "", -- A_Space_Adventure:ice01
 --      ["Congratulations, you are the best!"] = "", -- A_Space_Adventure:desert03
 --      ["Congratulations, you are the fastest!"] = "", -- A_Space_Adventure:moon02
@@ -409,18 +409,18 @@
 --      ["Corporationals"] = "", -- A_Classic_Fairytale:queen
 --      ["Corpsemonger"] = "", -- A_Classic_Fairytale:shadow
 --      ["Corpse Thrower"] = "", -- A_Classic_Fairytale:epil
---      ["Cost"] = "", -- Construction_Mode
---      ["Cost: %d"] = "", -- Construction_Mode
+--      ["Cost"] = "Ціна", -- Construction_Mode
+--      ["Cost: %d"] = "Ціна: %d", -- Construction_Mode
 --      ["Cotton Needer"] = "", -- Mutant
 --      ["Count Hogula"] = "", -- 
---      ["Coward"] = "", -- A_Classic_Fairytale:queen
+--      ["Coward"] = "Боягуз", -- A_Classic_Fairytale:queen
 --      ["Crate Before Attack: %s"] = "", -- WxW
 --      ["Crate Before Attack: You must collect a crate before you can attack."] = "", -- WxW
 --      ["Crate Placer"] = "", -- Construction_Mode
 --      ["Crates: Crates drop more often with a higher chance of bonus ammo"] = "", -- Battalion
 --      ["Crates: Crates drop randomly and may be empty"] = "", -- Battalion
 --      ["Crates: Crates drop randomly with chance of being empty"] = "", -- Battalion
---      ["Crates left: %d"] = "", -- User_Mission_-_RCPlane_Challenge
+--      ["Crates left: %d"] = "Залишилось ящиків: %d", -- User_Mission_-_RCPlane_Challenge
         ["Crates Left:"] = "Залишилось ящиків:", -- User_Mission_-_RCPlane_Challenge
 --      ["Crates per turn: %d"] = "", -- WxW
 --      ["crate(s)"] = "", -- SpeedShoppa
@@ -444,12 +444,12 @@
 --      ["+%d Ammo"] = "", -- Space_Invasion
         ["Dangerous Ducklings"] = "Небезпечні Каченята",
 --      ["Dark Strawberry"] = "", -- A_Space_Adventure:fruit02
---      ["+%d"] = "", -- Battalion
+--      ["+%d"] = "+%d", -- Battalion
 --      ["%d crate(s) remaining"] = "", -- SpeedShoppa
 --      ["%d damage was dealt in this game."] = "", -- Mutant
---      ["%d / %d"] = "", -- Battalion
---      ["%d | %d"] = "", -- Mutant
---      ["%d/%d"] = "", -- SpeedShoppa
+--      ["%d / %d"] = "%d / %d", -- Battalion
+--      ["%d | %d"] = "%d | %d", -- Mutant
+--      ["%d/%d"] = "%d/%d", -- SpeedShoppa
 --      ["Deadly Grape"] = "", -- A_Space_Adventure:fruit02
         ["Deadweight"] = "Власна вага",
 --      ["Deal 15 damage + 10% of your hog’s health to all hogs around you and get 2/3 back."] = "", -- Continental_supplies
@@ -468,19 +468,19 @@
 --      ["Deletion Mode"] = "", -- HedgeEditor
 --      ["Deletition Mode"] = "", -- HedgeEditor
         ["Demolition is fun!"] = "Руйнування це весело!",
---      ["Demo"] = "", -- The_Specialists
+--      ["Demo"] = "Демо", -- The_Specialists
 --      ["Dense Cloud"] = "", -- A_Classic_Fairytale:backstab, A_Classic_Fairytale:dragon, A_Classic_Fairytale:enemy, A_Classic_Fairytale:epil, A_Classic_Fairytale:family, A_Classic_Fairytale:journey, A_Classic_Fairytale:queen, A_Classic_Fairytale:shadow, A_Classic_Fairytale:united
 --      ["Dense Cloud must have already told them everything..."] = "", -- A_Classic_Fairytale:shadow
 --      ["Dense Cloud?! What are you doing?!"] = "", -- A_Classic_Fairytale:queen
---      ["Depleted Kamikaze! +5 points!"] = "", -- Space_Invasion
+--      ["Depleted Kamikaze! +5 points!"] = "Виснажений Камікадзе! +5 очок!", -- Space_Invasion
 --      ["Derp"] = "", -- User_Mission_-_Nobody_Laugh
---      ["Desert Storm"] = "", -- 
+--      ["Desert Storm"] = "Пустельний шторм", -- 
 --      ["Destroy all targets with no more than 10 bazookas."] = "", -- Basic_Training_-_Bazooka
 --      ["Destroy all targets with no more than 5 bazookas."] = "", -- Basic_Training_-_Bazooka
 --      ["Destroy all the targets!"] = "", -- Basic_Training_-_Bazooka, Basic_Training_-_Grenade
 --      ["Destroyer of planes"] = "", -- User_Mission_-_RCPlane_Challenge
 --      ["Destroy him, Leaks A Lot! He is responsible for the deaths of many of us!"] = "", -- A_Classic_Fairytale:first_blood
---      ["Destroy invaders and collect bonuses to score points."] = "", -- Space_Invasion
+--      ["Destroy invaders and collect bonuses to score points."] = "Знищіть загарбників і зберіть бонуси, щоб набрати очки.", -- Space_Invasion
 --      ["Destroy the targets!"] = "", -- Basic_Training_-_Bazooka, Basic_Training_-_Grenade
 --      ["Destroy the targets!|Hint: Select the Shoryuken and hit [Space]|P.S. You can use it mid-air."] = "", -- A_Classic_Fairytale:first_blood
 --      ["Destroy the targets!|Hint: [Up], [Down] to aim, [Space] to shoot"] = "", -- A_Classic_Fairytale:first_blood
@@ -496,8 +496,8 @@
 --      ["Did you really think that we needed the help of one of you?"] = "", -- A_Classic_Fairytale:queen
 --      ["Did you see him coming?"] = "", -- A_Classic_Fairytale:shadow
 --      ["Did you warn the village?"] = "", -- A_Classic_Fairytale:shadow
---      ["Die, die, die!"] = "", -- A_Classic_Fairytale:dragon
---      ["Difficulty: "] = "", -- Continental_supplies
+--      ["Die, die, die!"] = "Вмри, вмри, вмри!", -- A_Classic_Fairytale:dragon
+--      ["Difficulty: "] = "Складність: ", -- Continental_supplies
 --      ["Difficulty: Easy"] = "", -- A_Classic_Fairytale:first_blood
 --      ["Difficulty: Hard"] = "", -- A_Classic_Fairytale:first_blood
 --      ["Dimitry"] = "", -- 
@@ -523,7 +523,7 @@
 --      ["Don't hit yourself!"] = "", -- Basic_Training_-_Bazooka
 --      ["Don't touch the flames!"] = "", -- ClimbHome
 --      ["Don't you dare harming our tribe!"] = "", -- A_Classic_Fairytale:queen
---      ["Double kill!"] = "", -- Mutant
+--      ["Double kill!"] = "Подвійне вбивство!", -- Mutant
         ["Double Kill!"] = "Подвійне Вбивство!",
 --      ["Do you have any idea how bad an exploding arrow hurts?"] = "", -- A_Classic_Fairytale:queen
 --      ["Do you have any idea how valuable grass is?"] = "", -- A_Classic_Fairytale:enemy
@@ -544,14 +544,14 @@
         ["Drills"] = "Дрелі", -- A_Classic_Fairytale:backstab
 --      ["Dr. Jenner"] = "", -- 
 --      ["Dr. Jung"] = "", -- 
---      ["Drone Hunter! +10 points!"] = "", -- Space_Invasion
+--      ["Drone Hunter! +10 points!"] = "Мисливець за Джмелями! +10 очок!", -- Space_Invasion
 --      ["Drop a ball of dirt which turns into a|cluster on impact. Doesn’t end turn."] = "", -- Continental_supplies
 --      ["Drop a bomb: [Drop some heroic wind that will turn into a bomb on impact]"] = "", -- Continental_supplies
 --      ["- Dropped flags may be returned or recaptured"] = "", -- Capture_the_Flag
 --      ["Dropping a weapon while in water would just drown it, but launching one would work."] = "", -- Basic_Training_-_Flying_Saucer
 --      ["Drop weapon (while on rope): [Long Jump]"] = "", -- Basic_Training_-_Rope
         ["Drowner"] = "Потопаючий",
---      ["Dr. Parkinson"] = "", -- 
+--      ["Dr. Parkinson"] = "Доктор Паркінсон", -- 
 --      ["Drunk greenhorn"] = "", -- User_Mission_-_RCPlane_Challenge
 --      ["Drunk with power, perhaps!"] = "", -- A_Classic_Fairytale:queen
 --      ["%d sec"] = "", -- Construction_Mode
@@ -589,7 +589,7 @@
 --      ["Eckles"] = "", -- User_Mission_-_Nobody_Laugh
 --      ["Eclipse"] = "", -- Big_Armory
 --      ["Editing Commands: (Use while no weapon is selected)"] = "", -- HedgeEditor
---      ["Ehm, okay ..."] = "", -- A_Space_Adventure:moon01
+--      ["Ehm, okay ..."] = "Гм, гаразд ...", -- A_Space_Adventure:moon01
 --      ["Elderbot"] = "", -- A_Classic_Fairytale:family
 --      ["Elimate your captor."] = "", -- User_Mission_-_The_Great_Escape
         ["Eliminate all targets before your time runs out.|You have unlimited ammo for this mission."] = "Знищіть всі цілі до закінчення часу.|У вас безмежні боєприпаси.", --Bazooka, Shotgun, SniperRifle
@@ -606,13 +606,13 @@
 --      ["Enabled"] = "", -- WxW
 --      ["Enemy kills: Collect victim's weapons and +%d%% of its base health"] = "", -- Battalion
         ["Energetic Engineer"] = "Енергетичний Інженер",
---      ["Engineer"] = "", -- HedgeEditor, The_Specialists
+--      ["Engineer"] = "Інженер", -- HedgeEditor, The_Specialists
         ["Enjoy the swim..."] = "Насолоджуйся плаванням...",
 --      ["Entered boredom phase! Discrepancies detected …"] = "", -- A_Classic_Fairytale:queen
 --      ["Epilogue"] = "", -- A_Classic_Fairytale:epil
 --      ["ERROR [getHogInfo]: Hog is nil!"] = "", -- Battalion
 --      ["Eugene"] = "", -- 
---      ["Europe"] = "", -- Continental_supplies
+--      ["Europe"] = "Європа", -- Continental_supplies
         ["Everyone knows this."] = "Кожен це знає.", -- A_Classic_Fairytale:enemy
         ["Every single time!"] = "КОжного разу!", -- A_Classic_Fairytale:dragon
 --      ["Everything looks OK..."] = "", -- A_Classic_Fairytale:enemy
@@ -693,17 +693,17 @@
 --      ["Fruit"] = "", -- 
 --      ["Fruit Assassins"] = "", -- A_Space_Adventure:fruit02
 --      ["Fruity"] = "", -- 
---      ["Fuel: %d"] = "", -- Tumbler
+--      ["Fuel: %d"] = "Пальне: %d", -- Tumbler
 --      ["Fuzzy Beard"] = "", -- 
 --      ["“g=150”, where 150 is 150% of normal gravity."] = "", -- Gravity
 --      ["“g=50, g2=150, period=4000” for gravity changing|from 50 to 150 and back with period of 4000 ms."] = "", -- Gravity
---      ["Galaxy Guardians"] = "", -- Big_Armory
+--      ["Galaxy Guardians"] = "Охоронці Галактики", -- Big_Armory
         ["Game Modifiers: "] = "Модифікатори Гри: ",
---      ["Game over!"] = "", -- Space_Invasion
+--      ["Game over!"] = "Кінець гри!", -- Space_Invasion
         ["GAME OVER!"] = "КІНЕЦЬ ГРИ!",
         ["Game Started!"] = "Гра почалась!",
         ["Game? Was this a game to you?!"] = "Гра? Це для тебе була лише гра?!", -- A_Classic_Fairytale:enemy
---      ["Gangsters"] = "", -- 
+--      ["Gangsters"] = "Гангстери", -- 
 --      ["GasBomb"] = "", -- Continental_supplies
 --      ["Gas Gargler"] = "", -- A_Classic_Fairytale:queen
 --      ["Gasp! A smuggler!"] = "", -- A_Space_Adventure:desert01
@@ -748,7 +748,7 @@
 --      ["Glassy"] = "", -- 
 --      ["Goal Definition Mode"] = "", -- HedgeEditor
 --      ["GOAL DEFINITION MODE"] = "", -- HedgeEditor
---      ["Goal: Score %d points or more to win!"] = "", -- Mutant
+--      ["Goal: Score %d points or more to win!"] = "Мета: Наберіть %d очок чи більше для перемоги!", -- Mutant
 --      ["Go and collect the crate"] = "", -- A_Space_Adventure:cosmos
 --      ["Godai"] = "", -- 
 --      ["Go down and save these PAotH hogs!"] = "", -- A_Space_Adventure:moon01
@@ -814,7 +814,7 @@
 --      ["Guards"] = "", -- A_Space_Adventure:cosmos
 --      ["Guile"] = "", -- 
         ["Guys, do you think there's more of them?"] = "Хлопці, думаєте їх ще більше?", -- A_Classic_Fairytale:backstab
---      ["Haha! Come!"] = "", -- A_Classic_Fairytale:queen
+--      ["Haha! Come!"] = "Хаха! Ходи!", -- A_Classic_Fairytale:queen
         ["Hahahaha!"] = "Хахахаха!",
 --      ["Haha, I love the look on your face!"] = "", -- A_Classic_Fairytale:queen
         ["Haha, now THAT would be something!"] = "Хаха, от ЦЕ буде щось!",
@@ -900,7 +900,7 @@
 --      ["Hey, Hog Solo! Finally you have come!"] = "", -- A_Space_Adventure:moon01
 --      ["Hey! I was supposed to collect it!"] = "", -- A_Space_Adventure:fruit02
 --      ["Hey, %s! Look, someone is stealing the saucer!"] = "", -- A_Space_Adventure:cosmos
---      ["Hey! This is cheating!"] = "", -- A_Classic_Fairytale:journey
+--      ["Hey! This is cheating!"] = "Ей! Так не чесно!", -- A_Classic_Fairytale:journey
 --      ["Hidden"] = "", -- portal
 --      ["High Gravity: Gravity is %i%%"] = "", -- Gravity
 --      ["High Jump: [Backspace]"] = "", -- Basic_Training_-_Movement
@@ -1236,8 +1236,8 @@
 --      ["Jimmy"] = "", -- 
 --      ["Jingo"] = "", -- 
 --      ["Joe"] = "", -- A_Space_Adventure:moon01
---      ["John"] = "", -- A_Classic_Fairytale:journey
---      ["John Snow"] = "", -- A_Space_Adventure:ice01
+--      ["John"] = "Джон", -- A_Classic_Fairytale:journey
+--      ["John Snow"] = "Джон Сноу", -- A_Space_Adventure:ice01
 --      ["Jolly Roger"] = "", -- 
 --      ["Jones"] = "", -- 
 --      ["Judas"] = "", -- A_Classic_Fairytale:backstab
@@ -1251,7 +1251,7 @@
 --      ["Kaboom!"] = "", -- Basic_Training_-_Flying_Saucer
 --      ["Kaboom! Hahahaha! Take this, stupid meteorite!"] = "", -- A_Space_Adventure:final
 --      ["Kamikaze"] = "", -- Construction_Mode
---      ["Kamikaze Expert! +15 points!"] = "", -- Space_Invasion
+--      ["Kamikaze Expert! +15 points!"] = "Камікадзе Експерт! +15 очок!", -- Space_Invasion
         ["Keep it up!"] = "Так тримати!",
 --      ["Ken"] = "", -- 
 --      ["Kenshi"] = "", -- 
@@ -1262,23 +1262,23 @@
         ["Killing spree!"] = "Череда вбивств!",
 --      ["Killing the specialists"] = "", -- A_Space_Adventure:death02
 --      ["KILL IT!"] = "", -- A_Classic_Fairytale:first_blood
---      ["Kills: %d"] = "", -- Space_Invasion
+--      ["Kills: %d"] = "Вбивств: %d", -- Space_Invasion
 --      ["Kill the aliens!"] = "", -- A_Classic_Fairytale:dragon
 --      ["Kill the cannibal!"] = "", -- A_Classic_Fairytale:first_blood
 --      ["Kill The Leader"] = "", -- WxW
 --      ["Kill The Leader: You must also hit the team with the most health."] = "", -- WxW
 --      ["Kill the traitor, %s, or spare his life!"] = "", -- A_Classic_Fairytale:backstab
---      ["--- King ---"] = "", -- Battalion
---      ["King"] = "", -- Battalion
+--      ["--- King ---"] = "--- Король ---", -- Battalion
+--      ["King"] = "Король", -- Battalion
 --      ["King Customer"] = "", -- Challenge_-_Speed_Shoppa_-_ShoppaKing
 --      ["--- King Mode ---"] = "", -- Battalion
---      ["Knight"] = "", -- Battalion
+--      ["Knight"] = "Лицар", -- Battalion
 --      ["Knives"] = "", -- 
 --      ["Knockball"] = "", -- Knockball
 --      ["Knockball weapon"] = "", -- Knockball
 --      ["Knock off the enemies from the left-most place of the map!"] = "", -- A_Space_Adventure:fruit01
 --      ["koda"] = "", -- 
---      ["Kostya"] = "", -- 
+--      ["Kostya"] = "Костя", -- 
 --      ["Lady Mango"] = "", -- A_Space_Adventure:fruit01, A_Space_Adventure:fruit02
 --      ["LandFlag Modification Mode"] = "", -- HedgeEditor
 --      ["Land mines explode instantly."] = "", -- User_Mission_-_Teamwork_2
@@ -1385,15 +1385,15 @@
 --      ["Mine Placement Mode"] = "", -- Construction_Mode
 --      ["MINE PLACEMENT MODE"] = "", -- HedgeEditor
 --      ["Mines explode after %d s."] = "", -- Mutant
---      ["Mines time: 0s-5s"] = "", -- SimpleMission
---      ["Mines time: 0 seconds"] = "", -- portal, User_Mission_-_Spooky_Tree, User_Mission_-_Teamwork, User_Mission_-_The_Great_Escape, A_Space_Adventure:desert01, A_Space_Adventure:final, A_Space_Adventure:fruit02, A_Space_Adventure:ice01
---      ["Mines time: 1.5 seconds"] = "", -- A_Space_Adventure:death01
---      ["Mines time: %.1fs"] = "", -- SimpleMission
---      ["Mines time: 1 second"] = "", -- User_Mission_-_Diver, User_Mission_-_Newton_and_the_Hammock, A_Space_Adventure:desert02
---      ["Mines time: %.2fs"] = "", -- SimpleMission
---      ["Mines time: 3 seconds"] = "", -- A_Classic_Fairytale:journey
---      ["Mines time: 5 seconds"] = "", -- A_Classic_Fairytale:dragon, A_Classic_Fairytale:family, A_Classic_Fairytale:journey
---      ["Mines time: %ds"] = "", -- SimpleMission
+--      ["Mines time: 0s-5s"] = "Час детонування мін: 0с-5с", -- SimpleMission
+--      ["Mines time: 0 seconds"] = "Час детонування мін: 0 секунд", -- portal, User_Mission_-_Spooky_Tree, User_Mission_-_Teamwork, User_Mission_-_The_Great_Escape, A_Space_Adventure:desert01, A_Space_Adventure:final, A_Space_Adventure:fruit02, A_Space_Adventure:ice01
+--      ["Mines time: 1.5 seconds"] = "Час детонування мін: 1.5 секунди", -- A_Space_Adventure:death01
+--      ["Mines time: %.1fs"] = "Час детонування мін: %.2fс", -- SimpleMission
+--      ["Mines time: 1 second"] = "Час детонування мін: 1 секунда", -- User_Mission_-_Diver, User_Mission_-_Newton_and_the_Hammock, A_Space_Adventure:desert02
+--      ["Mines time: %.2fs"] = "Час детонування мін: %.2fс", -- SimpleMission
+--      ["Mines time: 3 seconds"] = "Час детонування мін: 3 секунди", -- A_Classic_Fairytale:journey
+--      ["Mines time: 5 seconds"] = "Час детонування мін: 5 секунд", -- A_Classic_Fairytale:dragon, A_Classic_Fairytale:family, A_Classic_Fairytale:journey
+--      ["Mines time: %ds"] = "Час детонування мін: %dс", -- SimpleMission
 --      ["Mine Strike"] = "", -- Construction_Mode
 --      ["Minion"] = "", -- A_Space_Adventure:moon01
 --      ["Minions"] = "", -- A_Space_Adventure:moon01
@@ -1428,7 +1428,7 @@
         ["Movement: [Up], [Down], [Left], [Right]"] = "Керування: [Вверх], [Вниз], [Вліво], [Вправо]",
 --      ["Mr Mango"] = "", -- A_Space_Adventure:fruit01
 --      ["Mudkip"] = "", -- 
---      ["Multi-shot! +15 points!"] = "", -- Space_Invasion
+--      ["Multi-shot! +15 points!"] = "Мультипостріл! +15 очок!", -- Space_Invasion
 --      ["Multi-Use: You can take and use the same ammo type multiple times in a turn"] = "", -- Highlander
 --      ["Muriel"] = "", -- A_Classic_Fairytale:backstab, A_Classic_Fairytale:dragon, A_Classic_Fairytale:family, A_Classic_Fairytale:queen
 --      ["Muscle Dissolver"] = "", -- A_Classic_Fairytale:shadow
@@ -1451,12 +1451,12 @@
 --      ["Near Secret Base 17 of PAotH in the rural Hogland ..."] = "", -- A_Space_Adventure:cosmos
 --      ["nemo"] = "", -- 
 --      ["Neutralize your enemies and be careful!"] = "", -- A_Space_Adventure:moon01
---      ["New barrels per turn: %d"] = "", -- Tumbler
---      ["New clan record: %.1fs"] = "", -- Racer, TechRacer
+--      ["New barrels per turn: %d"] = "Нових бочок на хід: %d", -- Tumbler
+--      ["New clan record: %.1fs"] = "Новий рекорд клану: %.1fс", -- Racer, TechRacer
         ["NEW fastest lap: "] = "НОВА найшвидша партія: ",
---      ["New mines per turn: %d"] = "", -- Tumbler
---      ["New race record: %.1fs"] = "", -- Racer, TechRacer
---      ["Newton and the Hammock"] = "", -- User_Mission_-_Newton_and_the_Hammock
+--      ["New mines per turn: %d"] = "Нових мін на хід: %d", -- Tumbler
+--      ["New race record: %.1fs"] = "Новий рекорд гонки: %.1fс", -- Racer, TechRacer
+--      ["Newton and the Hammock"] = "Ньютон і Гамак", -- User_Mission_-_Newton_and_the_Hammock
 --      ["Next target is ready!"] = "", -- Basic_Training_-_Flying_Saucer
 --      ["Next time you play \"Searching in the dust\" you'll have an RC plane available."] = "", -- A_Space_Adventure:desert03
 --      ["Nice!"] = "", -- A_Space_Adventure:cosmos
@@ -1556,7 +1556,7 @@
 --      ["Okay then!"] = "", -- A_Space_Adventure:fruit02
 --      ["Okay, then you have to go and take some of the weapons we have hidden in case of an emergency!"] = "", -- A_Space_Adventure:moon01
 --      ["Old One Eye"] = "", -- 
---      ["Oleg"] = "", -- 
+--      ["Oleg"] = "Олег", -- 
 --      ["Olive"] = "", -- A_Classic_Fairytale:united
 --      ["Omnivore"] = "", -- A_Classic_Fairytale:first_blood
 --      ["Once upon a time, on an island with great natural resources, lived two tribes in heated conflict..."] = "", -- A_Classic_Fairytale:first_blood
@@ -1619,7 +1619,7 @@
 --      ["Pincer Knights"] = "", -- Bazooka_Battlefield
 --      ["Pings left: %d"] = "", -- Space_Invasion
 --      ["Pink"] = "", -- 
---      ["Pirates"] = "", -- 
+--      ["Pirates"] = "Пірати", -- 
 --      ["Place 2-%d waypoints using the waypoint placement tool."] = "", -- Racer
 --      ["Place 2 waypoints using the waypoint placement tool."] = "", -- Racer
 --      ["Place air mines"] = "", -- HedgeEditor
@@ -1720,8 +1720,8 @@
 --      ["Pyro"] = "", -- HedgeEditor, The_Specialists
 --      ["Pyromancer"] = "", -- Battalion
 --      ["Quit: [Esc]"] = "", -- Basic_Training_-_Movement
---      ["Race complexity limit reached"] = "", -- Racer, TechRacer
---      ["Racer"] = "", -- Racer
+--      ["Race complexity limit reached"] = "Досягнута межа складності гонки", -- Racer, TechRacer
+--      ["Racer"] = "Гонщик", -- Racer
 --      ["Racer tool"] = "", -- Racer
 --      ["Race"] = "", -- TrophyRace
 --      ["Rachel"] = "", -- A_Classic_Fairytale:dragon, A_Classic_Fairytale:family, A_Classic_Fairytale:queen
@@ -1791,10 +1791,10 @@
 --      ["Rotten"] = "", -- 
 --      ["Round draw"] = "", -- Racer, TechRacer
 --      ["Round %d (Sudden Death in round %d)"] = "", -- Battalion
---      ["Round limit: %d"] = "", -- Racer
---      ["Round Limit: %d"] = "", -- Space_Invasion
+--      ["Round limit: %d"] = "Межа раунду: %d", -- Racer
+--      ["Round Limit: %d"] = "Межа Раунду: %d", -- Space_Invasion
 --      ["Round limit:"] = "", -- TechRacer
---      ["Rounds complete: %d/%d"] = "", -- Racer, Space_Invasion, TechRacer
+--      ["Rounds complete: %d/%d"] = "Раундів завершено: %d/%d", -- Racer, Space_Invasion, TechRacer
 --      ["Round's slowest lap: %.3fs by %s"] = "", -- TrophyRace
 --      ["Rounds until Sudden Death: %d"] = "", -- Battalion
 --      ["RS1"] = "", -- A_Space_Adventure:fruit03
@@ -1803,8 +1803,8 @@
 --      ["Rubber Placement Mode"] = "", -- Construction_Mode
 --      ["RUBBER PLACEMENT MODE"] = "", -- HedgeEditor
 --      ["Rules:"] = "", -- Capture_the_Flag
---      ["RULES:"] = "", -- Frenzy
---      ["Rules: "] = "", -- Mutant
+--      ["RULES:"] = "ПРАВИЛА:", -- Frenzy
+--      ["Rules: "] = "Правила: ", -- Mutant
 --      ["Run away, you coward!"] = "", -- A_Space_Adventure:desert01
 --      ["Running displacement algorithm …"] = "", -- A_Classic_Fairytale:queen
 --      ["Running for survival"] = "", -- A_Space_Adventure:desert02
@@ -1923,14 +1923,14 @@
 --      ["sheepluva"] = "", -- 
 --      ["Sheepy"] = "", -- 
 --      ["She's behind that tall thingy."] = "", -- A_Classic_Fairytale:family
---      ["Shield boosted! +%d power"] = "", -- Space_Invasion
---      ["Shield depleted"] = "", -- Space_Invasion
+--      ["Shield boosted! +%d power"] = "Щит підсилено! +%d сили", -- Space_Invasion
+--      ["Shield depleted"] = "Щит вичерпаний", -- Space_Invasion
         ["Shield is fully recharged!"] = "Щит повністю заряджений!",
---      ["Shield Master! +10 points!"] = "", -- Space_Invasion
---      ["Shield Miser! +%d points!"] = "", -- Space_Invasion
---      ["Shield OFF: %d power remaining"] = "", -- Space_Invasion
---      ["Shield ON: %d power remaining"] = "", -- Space_Invasion
---      ["Shield Seeker! +10 points!"] = "", -- Space_Invasion
+--      ["Shield Master! +10 points!"] = "Майстер Щита! +10 очок!", -- Space_Invasion
+--      ["Shield Miser! +%d points!"] = "Скупій Щита! +%d очок!", -- Space_Invasion
+--      ["Shield OFF: %d power remaining"] = "Щит Вимкнено: %d сили залишилось", -- Space_Invasion
+--      ["Shield ON: %d power remaining"] = "Щит Ввімкнено: %d сили залишилось", -- Space_Invasion
+--      ["Shield Seeker! +10 points!"] = "Шукач Щита! +10 очок!", -- Space_Invasion
 --      ["Shinobi"] = "", -- 
 --      ["%s hit the ground."] = "", -- User_Mission_-_Rope_Knock_Challenge
 --      ["Shoppa Love"] = "", -- Challenge_-_Speed_Shoppa_-_Hedgelove
@@ -1982,7 +1982,7 @@
 --      ["So, I believe that it's a good place to start."] = "", -- A_Space_Adventure:desert01
 --      ["So, I kindly ask for your help."] = "", -- A_Space_Adventure:fruit01
 --      ["So I shook my fist in the air!"] = "", -- A_Classic_Fairytale:epil
---      ["Soldier"] = "", -- HedgeEditor, The_Specialists
+--      ["Soldier"] = "Солдат", -- HedgeEditor, The_Specialists
 --      ["So, let me tell you what I know about Professor Hogevil."] = "", -- A_Space_Adventure:moon02
 --      ["Some parts of the land are indestructible."] = "", -- A_Space_Adventure:fruit03
 --      ["Some sick game of yours?!"] = "", -- A_Classic_Fairytale:queen
@@ -2163,14 +2163,14 @@
 --      ["Targets left: %d"] = "", -- TargetPractice
 --      ["Tatsujin"] = "", -- 
 --      ["Tatters"] = "", -- 
---      ["Team %d"] = "", -- SimpleMission
+--      ["Team %d"] = "Команда %d", -- SimpleMission
         ["Team %d: "] = "Команда %d: ",
 --      ["Team Identity Mode"] = "", -- HedgeEditor
 --      ["TEAM IDENTITY MODE"] = "", -- HedgeEditor
 --      ["Team of Hearts"] = "", -- Challenge_-_Speed_Shoppa_-_Hedgelove
 --      ["Teams are tied! Continue playing rounds until we have a winner!"] = "", -- Space_Invasion
---      ["Team Scores:"] = "", -- Control
---      ["Team scores:"] = "", -- Space_Invasion
+--      ["Team Scores:"] = "Очки Команди", -- Control
+--      ["Team scores:"] = "Очки команди", -- Space_Invasion
 --      ["Teamwork 2"] = "", -- User_Mission_-_Teamwork_2
 --      ["Teamwork"] = "", -- User_Mission_-_Teamwork
 --      ["Team Zook"] = "", -- Target_Practice_-_Bazooka_easy, Target_Practice_-_Bazooka_hard
@@ -2210,7 +2210,7 @@
 --      ["That's why he always wears a hat since then."] = "", -- A_Space_Adventure:moon02
 --      ["That traitor won't be killing us anymore!"] = "", -- A_Classic_Fairytale:queen
 --      ["That was just mean!"] = "", -- A_Classic_Fairytale:backstab, A_Classic_Fairytale:united
---      ["That was pointless. The flag will respawn next round."] = "", -- CTF_Blizzard
+--      ["That was pointless. The flag will respawn next round."] = "Це було безглуздо. Прапор з'явиться знов у наступному раунді.", -- CTF_Blizzard
 --      ["The adventure begins!"] = "", -- A_Space_Adventure:cosmos
 --      ["The air bombs are weaker than usual."] = "", -- Battalion
 --      ["The aliens respect me, even worship me!"] = "", -- A_Classic_Fairytale:queen
@@ -2406,15 +2406,15 @@
 --      ["Thug #%d"] = "", -- A_Space_Adventure:death01
 --      ["Tie-breaking round %d"] = "", -- Space_Invasion
 --      ["Timbers"] = "", -- 
---      ["Time: %.1fs"] = "", -- Racer, TechRacer
+--      ["Time: %.1fs"] = "Час: %.1fс", -- Racer, TechRacer
 --      ["Time: %.3fs by %s"] = "", -- TrophyRace
---      ["Time: %.3fs"] = "", -- TrophyRace
+--      ["Time: %.3fs"] = "Час: %.3fс", -- TrophyRace
 --      ["Time Box"] = "", -- Construction_Mode
---      ["Timed Kamikaze! +10 points!"] = "", -- Space_Invasion
---      ["Time extended! +%dsec"] = "", -- Space_Invasion
---      ["Time extension: %ds"] = "", -- Tumbler
+--      ["Timed Kamikaze! +10 points!"] = "Часовий Камікадзе! +10 очок!", -- Space_Invasion
+--      ["Time extended! +%dsec"] = "Час продовжено! +%dсек", -- Space_Invasion
+--      ["Time extension: %ds"] = "Збільшення часу: %dс", -- Tumbler
 --      ["Time for a more interesting stunt, but first just collect the next crate!"] = "", -- Basic_Training_-_Flying_Saucer
---      ["Timer"] = "", -- Basic_Training_-_Grenade
+--      ["Timer"] = "Таймер", -- Basic_Training_-_Grenade
 --      ["Time's up!"] = "", -- Basic_Training_-_Sniper_Rifle, SpeedShoppa, Space_Invasion
 --      ["Time’s up!"] = "", -- TargetPractice
 --      ["Time to run!"] = "", -- A_Space_Adventure:fruit01
@@ -2438,7 +2438,7 @@
 --      ["Toggle Gear Information: [Precise]+[3]"] = "", -- HedgeEditor
 --      ["Toggle Help: [Precise]+[1]"] = "", -- HedgeEditor
 --      ["Toggle Placement/Deletion: [Left], [Right]"] = "", -- HedgeEditor
---      ["Toggle Shield: [Long jump]"] = "", -- Space_Invasion
+--      ["Toggle Shield: [Long jump]"] = "Перемкнути Щит [Довгий стрибок]", -- Space_Invasion
 --      ["To help you, of course!"] = "", -- A_Classic_Fairytale:journey
 --      ["To launch a projectile in mid-flight, hold [Precise] and press [Long jump]."] = "", -- Basic_Training_-_Flying_Saucer
 --      ["Tony"] = "", -- 
@@ -2459,9 +2459,9 @@
 --      ["To win the game you have to pass into the rings in time."] = "", -- A_Space_Adventure:ice02
 --      ["To win the game you have to stand next to Thanta."] = "", -- A_Space_Adventure:ice01
         ["Toxic Team"] = "Токсична Команда", -- User_Mission_-_Diver, User_Mission_-_Spooky_Tree, User_Mission_-_Teamwork
---      ["Track completed!"] = "", -- Racer, TechRacer
+--      ["Track completed!"] = "Трасу пройдено", -- Racer, TechRacer
 --      ["Trainee"] = "", -- TargetPractice
---      ["Training"] = "", -- Basic_Training_-_Flying_Saucer, Basic_Training_-_Rope
+--      ["Training"] = "Тренування", -- Basic_Training_-_Flying_Saucer, Basic_Training_-_Rope
 --      ["Training complete!"] = "", -- Basic_Training_-_Flying_Saucer
 --      ["Training Team"] = "", -- TargetPractice
 --      ["Traitors"] = "", -- A_Classic_Fairytale:epil
@@ -2617,7 +2617,7 @@
 --      ["Water: Rises by 37 per turn"] = "", -- Battalion
 --      ["Waypoint Editing Mode"] = "", -- HedgeEditor
 --      ["WAYPOINT EDITING MODE"] = "", -- HedgeEditor
---      ["Waypoint placed. Available points remaining: %d"] = "", -- Racer
+--      ["Waypoint placed. Available points remaining: %d"] = "Точка шляху розміщена. Залишилось точок: %d", -- Racer
 --      ["Waypoint placement phase"] = "", -- Racer
 --      ["Waypoint removed. Available points: %d"] = "", -- Racer
 --      ["Waypoints remaining: %d"] = "", -- Racer, TechRacer
@@ -2749,7 +2749,7 @@
 --      ["Why do you not like me?"] = "", -- A_Classic_Fairytale:shadow
 --      ["Why do you want to take over our island?"] = "", -- A_Classic_Fairytale:enemy
 --      ["Why me?!"] = "", -- A_Classic_Fairytale:backstab
---      ["Why %s? Why?"] = "", -- A_Classic_Fairytale:backstab
+--      ["Why %s? Why?"] = "Чому %s? Чому?", -- A_Classic_Fairytale:backstab
 --      ["Why, why, why, why!"] = "", -- A_Classic_Fairytale:queen
 --      ["Why would they do this?"] = "", -- A_Classic_Fairytale:backstab
 --      ["- Will get 1-3 random weapons"] = "", -- Continental_supplies
--- a/share/hedgewars/Data/Locale/uk.txt	Fri Nov 09 14:12:00 2018 +0300
+++ b/share/hedgewars/Data/Locale/uk.txt	Fri Nov 09 14:15:22 2018 +0300
@@ -307,7 +307,7 @@
 04:00=Атакуй ворогів використовуючи просту гранату.|Вона вибухне як тільки її таймер доходить до нуля.|1-5: Вистав таймер гранати|Атака: Утримуй щоб метнути сильніше
 04:01=Атакуй ворогів використовуючи кластерну|бомбу. Вона розділиться на менші бомби|коли таймер досягає нуля.|1-5: Вистав таймер гранати|Атака: Утримуй щоб метнути сильніше
 04:02=Атакуй ворогів балістичним снарядом,|на політ якого впливає вітер.|Атака: Утримуй щоб стрельнути сильніше
-04:03=Запусти вибухо-небезпечну бджолу, яка|полетить до вибраної цілі. Не стріляй на|повну силу щоб поліпшити її точність.|Курсор: Вибери ціль|Атака: Утримуй щоб стрельнути сильніше
+04:03=Запусти вибухонебезпечну бджолу, яка|полетить до вибраної цілі. Не стріляй на|повну силу щоб поліпшити її точність.|Курсор: Вибери ціль|Атака: Утримуй щоб стрельнути сильніше
 04:04=Атакуй ворогів використовуючи рушницю з двома|пострілами.Завдяки її розмаху тобі не потрібні точні|попадання щоб зашкодити супернику.|Атака: Стріляй (кілька разів)
 04:05=Прямуй під землю! Візьми відбійний молоток,|просвердли в землі дірку та досягни інших областей.|Атака: Почни або заверши рити
 04:06=Засмутився? Немає можливості атакувати? Хочеш зберегти|боєприпаси? Без проблем! Просто пропусти хід, боягузе!|Атака: Пропусти свою чергу без бою
@@ -325,7 +325,7 @@
 04:18=Потрібний додатковий захист або хочеш пройти|непрохідну землю? Розмісти кілька балок як|тобі до вподоби.|Вліво/Вправо: Вибери потрібну балку|Курсор: Встанови балку в доступне місце
 04:19=Застосована в потрбний момент телепортація|може бути могутнішою більшості зброї,|оскільки дозволяє вберегти їжаків від|небезпечних ситуацій за лічені секунди.|Курсор: Вибери цільовий регіон
 04:20=Дозволяє здійснити поточний хід|іншим їжаком.|Атака: Ввімкни перемикання їжаків
-04:21=Стріляє гранато-подібним снарядом, який|при зіткненні розлетиться на декілька бомб.|Атака: Стріляй з всієї сили
+04:21=Стріляє гранатоподібним снарядом, який|при зіткненні розлетиться на декілька бомб.|Атака: Стріляй з всієї сили
 04:22=Не лише для Індіани Джонс! Батіг корисний|в багатьох ситуаціях. Особливо|коли треба штовхнути когось з кручі.|Атака: Бий все, що бачиш перед собою
 04:23=Коли нічого втрачати, це може бути|доречним. Принеси їжака в жертву, запустивши|його в певному напрямку та шкодячи всьому|на його шляху.В кінці шляху він вибухне.|Атака: Почни спустошливу та смертоносну атаку
 04:24=З днем народження! Запусти цей торт, нехай він|йде прямо до твоїх ворогів і влаштує їм вибухову|вечірку. Торт може пройти майже всюди|але може вибухнути раніше, ніж треба.|Атака: Запусти торт або хай зупиниться і вибухне
@@ -346,7 +346,7 @@
 04:39=Лети до іншої частини карти на літаючій тарілці.|Цей важко керований пристрій здатний перенести|тебе на практично будь-яку позицію поля бою.|Атака: Активувати|Вверх/Вліво/Вправо: Приклади зусилля в одному напрямку|Довгий Стрибок: Кинь гранати чи подібну зброю
 04:40=Покрий землю вогнем, використавши цю плашечку|наповнену горючою (незабаром) рідиною.|Атака: Утримуй щоб стрельнути сильніше
 04:41=Природа може переплюнути навіть літаючу|тарілку. Пташка може поносити їжака|навколо та скинути яйця на ворогів!|Атака: Активуй та скинь яйця|Вверх/Вліво/Вправо: Лети в одному напрямку
-04:42=Цей портативний портал здатний миттєво преренести|вас, ваших ворогів, чи ваше озброєння між двома|точками на місцевості.|Використовуйте його з розумом і ваша кампанія буде...|ДУЖЕ УСПІШНОЮ!|Атака: Вистріли портал|Переключити: Змінюй колір порталу
+04:42=Цей портативний портал здатний миттєво перенести|вас, ваших ворогів, чи ваше озброєння між двома|точками на місцевості.|Використовуйте його з розумом і ваша кампанія буде...|ДУЖЕ УСПІШНОЮ!|Атака: Вистріли портал|Переключити: Змінюй колір порталу
 04:43=Проведи свій музичний дебют з величезним|успіхом! Скинь фортепіано з небес, але май|на увазі...хтось повинен на ньому грати,|і це може коштувати тобі життя!|Курсор: Вкажи цільовий регіон|F1-F9: Грай на піаніно
 04:44=Це не просто сир, це біологічна зброя! Він не|нанесе багато шкоди, коли таймер досягне нуля,|але він точно отруїть всіх, хто відчув його запах!|1-5: Встановити таймер гранати|Атака: Утримуй щоб метнути сильніше
 04:45=Всі ці класи фізики нарешті окупились, пусти|руйнівну Синусну хвилю на ворогів. Бережись,|ця зброя не іграшка. (Ця зброя не завершена)|Атака: Стріляй
--- a/tools/find_outdated_engine_translations.sh	Fri Nov 09 14:12:00 2018 +0300
+++ b/tools/find_outdated_engine_translations.sh	Fri Nov 09 14:15:22 2018 +0300
@@ -33,8 +33,10 @@
 TEMP_EN=$(mktemp);
 TEMP_LANG=$(mktemp);
 
+#hg fa en.txt | grep -P "^\s*\d+:\s+0[013-6]:" > $TEMP_EN;
 hg blame en.txt | grep -P "^\s*\d+:\s+0[013-6]:" > $TEMP_EN;
 
+#hg fa $BLAMELANGFILE | grep -P "^\s*\d+:\s+0[013-6]:" > $TEMP_LANG;
 hg blame $BLAMELANGFILE | grep -P "^\s*\d+:\s+0[013-6]:" > $TEMP_LANG;
 
 cat $TEMP_EN | while read f;
@@ -48,7 +50,9 @@
         if (($REV>$OTHER_REV));
         then
             TEXT=$(echo $f | sed 's/^\s*[0-9]\+:\s*[0-9]\+:[0-9]\+=//');
-            OLD_TEXT=$(hg grep --all -r "1:$OTHER_REV" "$CODE" en.txt | tail -n1 | sed 's/.*en.txt:[0-9]\+:[+-]:[0-9]\+:[0-9]\+=//;s/
//');
+			# script runs ~20% faster than with blame but nonstandard
+            # OLD_TEXT=$(hg fa -r "$OTHER_REV" en.txt | grep -P "^\s*\d+:\s+${CODE}=" | sed 's/^\s*[0-9]\+:\s*[0-9]\+:[0-9]\+=//;s/
//');
+            OLD_TEXT=$(hg blame -r "$OTHER_REV" en.txt | grep -P "^\s*\d+:\s+${CODE}=" | sed 's/^\s*[0-9]\+:\s*[0-9]\+:[0-9]\+=//;s/
//');
 
             COMPARE_TEXT=$TEXT;
             COMPARE_OLD_TEXT=$OLD_TEXT;
@@ -67,9 +71,9 @@
                 else
                     printf '━%.0s' $(seq $COLUMNS);
                 fi;
-                echo "$TEXT ← Current English";
-                echo "$OLD_TEXT ← English at time of translation";
-                echo "$(echo $OTHER | sed 's/^\s*[0-9]\+:\s*[0-9]\{2\}:[0-9]\{2\}=//') ← current translation";
+                echo "${CODE}=$TEXT ← Current English";
+                echo "${CODE}=$OLD_TEXT ← English at time of translation";
+                echo "${CODE}=$(echo $OTHER | sed 's/^\s*[0-9]\+:\s*[0-9]\{2\}:[0-9]\{2\}=//') ← current translation";
             fi;
         fi;
     fi;