diff --git a/src/game_state.rs b/src/game_state.rs
index 7e6e08c7b21c29844a4cd5796afbde974e759d5f..bbdb7e09721e235062044f4eff93f51beadbd6af 100644
--- a/src/game_state.rs
+++ b/src/game_state.rs
@@ -5,6 +5,7 @@ mod enemy;
 mod textures;
 pub mod config;
 mod tile;
+mod combat_log;
 
 use tetra::{Context, State};
 use tetra::graphics::{self, Color, DrawParams};
@@ -15,6 +16,9 @@ use crate::game_state::tile::Tile;
 use tetra::math::Vec2;
 use std::cmp::min;
 use rand::{thread_rng, Rng};
+use tetra::graphics::text::{VectorFontBuilder, Font, Text};
+use crate::game_state::combat_log::PlayerAction;
+use crate::game_state::combat_log::PlayerAction::Move;
 
 type Point = (usize, usize);
 
@@ -22,18 +26,25 @@ pub struct GameState {
     current_run: Run,
     high_score: usize,
     textures: Textures,
+    font: Font,
 }
 
 impl GameState {
     pub fn new(ctx: &mut Context) -> tetra::Result<GameState> {
         let textures = Textures::init(ctx);
+        let font = VectorFontBuilder::new("./resources/corbel.ttf")?.with_size(ctx, 16.0);
 
         if textures.is_ok() {
-            Ok(GameState {
-                current_run: Run::new(),
-                high_score: 0,
-                textures: textures.unwrap(),
-            })
+            if font.is_ok() {
+                Ok(GameState {
+                    current_run: Run::new(),
+                    high_score: 0,
+                    textures: textures.unwrap(),
+                    font: font.unwrap(),
+                })
+            } else {
+                Err(font.err().unwrap())
+            }
         } else {
             Err(textures.err().unwrap())
         }
@@ -54,6 +65,8 @@ impl State for GameState {
         graphics::clear(ctx, Color::rgb(0.220, 0.220, 0.220));
 
         self.draw_board(ctx);
+        self.draw_stats(ctx);
+        self.draw_combat_log(ctx);
 
         Ok(())
     }
@@ -88,9 +101,12 @@ impl GameState {
 
         let target_tile = self.current_run.level.get_tile_at(target_position);
         match target_tile {
-            Tile::Empty => self.current_run.level.move_player_to(target_position),
+            Tile::Empty => {
+                self.current_run.level.move_player_to(target_position);
+                self.current_run.combat_log.player_action = Option::from(Move);
+            },
             Tile::Wall => return false,
-            _ => {}
+            _ => ()
         }
         true
     }
@@ -177,7 +193,6 @@ impl GameState {
 
 impl GameState {
     fn finish_turn(&mut self) {
-        self.current_run.turn_count += 1;
         self.current_run.level.turn_count += 1;
     }
 }
@@ -256,4 +271,58 @@ impl GameState {
             color: Color::WHITE,
         }
     }
+
+    fn draw_stats(&self, ctx: &mut Context) {
+        let text_top = GameState::calculate_text_top();
+        let health_string = format!("Health: {} / {}", self.current_run.player.current_hp, self.current_run.player.max_hp);
+        let turn_string = format!("Turn: {}", self.current_run.level.turn_count);
+        let level_string = format!("Level: {}       High Score: {}", self.current_run.level_count, self.high_score);
+
+        self.draw_string(health_string, 50.0, text_top, ctx);
+        self.draw_string(turn_string, 50.0, text_top + 25.0, ctx);
+        self.draw_string(level_string, 50.0, text_top + 50.0, ctx);
+    }
+
+    fn draw_combat_log(&self, ctx: &mut Context) {
+        self.draw_player_action(ctx);
+        self.draw_enemy_action(ctx);
+    }
+
+    fn draw_player_action(&self, ctx: &mut Context) {
+        let text_top = GameState::calculate_text_top();
+        match self.current_run.combat_log.player_action {
+            Some(PlayerAction::Move) =>
+                self.draw_string("You moved.".parse().unwrap(), 300.0, text_top, ctx),
+            Some(PlayerAction::Wait) =>
+                self.draw_string("You waited.".parse().unwrap(), 300.0, text_top, ctx),
+            Some(PlayerAction::Attack(damage_done, remaining_hp)) =>
+                self.draw_string(
+                    format!("You attacked for {} damage. The enemy has {} hit points remaining.", damage_done, remaining_hp),
+                    300.0,
+                    text_top,
+                    ctx
+                ),
+            None => ()
+        };
+    }
+
+    fn draw_enemy_action(&self, ctx: &mut Context) {
+        let text_top = GameState::calculate_text_top() + 25.0;
+
+        match self.current_run.combat_log.damage_taken {
+            Some(damage) =>
+                self.draw_string(format!("The enemy attacked you for {} damage.", damage), 300.0, text_top, ctx),
+
+            None => ()
+        };
+    }
+
+    fn draw_string(&self, string: String, x: f32, y: f32, ctx: &mut Context) {
+        Text::new(string, self.font.clone())
+            .draw(ctx, Vec2::new(x, y));
+    }
+
+    fn calculate_text_top() -> f32 {
+        33.0 * (config::BOARD_HEIGHT as f32 + 2.0) + 7.0
+    }
 }
\ No newline at end of file
diff --git a/src/game_state/combat_log.rs b/src/game_state/combat_log.rs
new file mode 100644
index 0000000000000000000000000000000000000000..dc7f853400879bf814b39bcd6224ed0f07b5dc34
--- /dev/null
+++ b/src/game_state/combat_log.rs
@@ -0,0 +1,12 @@
+#[derive(Debug)]
+pub struct CombatLog {
+    pub player_action: Option<PlayerAction>,
+    pub damage_taken: Option<usize>
+}
+
+#[derive(Debug, Copy, Clone)]
+pub enum PlayerAction {
+    Move,
+    Wait,
+    Attack(usize, usize) // damage, remaining hp
+}
\ No newline at end of file
diff --git a/src/game_state/config.rs b/src/game_state/config.rs
index 7d3faa87040fa27c983ceed2339a5740f82b1a18..85121bf2c42beceeff5c0e5b0a505b2b28fa4a3b 100644
--- a/src/game_state/config.rs
+++ b/src/game_state/config.rs
@@ -1,7 +1,7 @@
-pub const WINDOW_WIDTH: f32 = 1280.0;
-pub const WINDOW_HEIGHT: f32 = 720.0;
-pub const BOARD_WIDTH: usize = 35;
-pub const BOARD_HEIGHT: usize = 19;
+pub const WINDOW_WIDTH: f32 = 1920.0;
+pub const WINDOW_HEIGHT: f32 = 1080.0;
+pub const BOARD_WIDTH: usize = 50;
+pub const BOARD_HEIGHT: usize = 28;
 
 pub const PLAYER_STARTING_AP: usize = 1;
 pub const PLAYER_STARTING_HP: usize = 10;
diff --git a/src/game_state/player.rs b/src/game_state/player.rs
index d37c3279ae70308a570fd64ac453ffca6d5d8106..0da27545759256cb8525a1da38e34d201ca61fc5 100644
--- a/src/game_state/player.rs
+++ b/src/game_state/player.rs
@@ -1,7 +1,7 @@
 pub struct Player {
-    current_hp: usize,
-    max_hp: usize,
-    attack_power: usize,
+    pub current_hp: usize,
+    pub max_hp: usize,
+    pub attack_power: usize,
 }
 
 impl Player {
diff --git a/src/game_state/run.rs b/src/game_state/run.rs
index 5c909e7f0bdbfe71a0aa25c931f78e2ab608ffdb..9210411548af3df3ef64a38c1004302101d3cf0f 100644
--- a/src/game_state/run.rs
+++ b/src/game_state/run.rs
@@ -1,12 +1,13 @@
 use crate::game_state::player::Player;
 use crate::game_state::level::Level;
 use crate::game_state::config;
+use crate::game_state::combat_log::CombatLog;
 
 pub struct Run {
-    pub turn_count: usize,
-    level_count: usize,
-    player: Player,
+    pub level_count: usize,
+    pub player: Player,
     pub level: Level,
+    pub combat_log: CombatLog
 }
 
 impl Run {
@@ -15,10 +16,13 @@ impl Run {
         let ap = config::PLAYER_STARTING_AP;
 
         Run {
-            turn_count: 0,
             level_count: 0,
             player: Player::new(ap, hp),
             level: Level::new(0),
+            combat_log: CombatLog {
+                player_action: None,
+                damage_taken: None
+            }
         }
     }
 }
\ No newline at end of file
diff --git a/src/main.rs b/src/main.rs
index c79c92fd7b5de5a2f847ff9779a0d771a6f5aaf3..6033692eef76bb8527adf571f540be99e989f64b 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -1,315 +1,13 @@
-use std::collections::HashMap;
-use tetra::graphics::text::{Font, Text, VectorFontBuilder};
-use tetra::graphics::{self, Color, DrawParams, Texture};
-use tetra::input::{self, Key};
-use tetra::math::Vec2;
-use tetra::{Context, ContextBuilder, State};
-use rand::{thread_rng, Rng};
+mod game_state;
 
+use tetra::ContextBuilder;
 
-//constants
-const WINDOW_WIDTH: f32 = 1920.0;
-const WINDOW_HEIGHT: f32 = 1080.0;
-const BOARD_WIDTH: usize = 58;
-const BOARD_HEIGHT: usize = 28;
+use crate::game_state::GameState;
+use crate::game_state::config;
 
 fn main() -> tetra::Result {
-    ContextBuilder::new("rusttest", WINDOW_WIDTH as i32, WINDOW_HEIGHT as i32)
+    ContextBuilder::new("rusttest", config::WINDOW_WIDTH as i32, config::WINDOW_HEIGHT as i32)
         .quit_on_escape(true)
         .build()?
         .run(GameState::new)
 }
-
-struct GameState {
-player: Entity,
-foes: Foes,
-tile: Texture,
-world: World,
-ui: UI,
-stats: Stats,
-}
-
-impl GameState {
-    fn new(ctx: &mut Context) -> tetra::Result<GameState> {
-        //load graphics
-        let player_texture = Texture::new(ctx, "./resources/player.png")?;
-        let tile_texture = Texture::new(ctx, "./resources/tile.png")?;
-
-        //set initial position
-        let player_position = Vec2::new(5,7);
-
-        //UI
-        let font = VectorFontBuilder::new("./resources/corbel.ttf")?;
-        let font2 = font.with_size(ctx, 16.0)?;
-
-        Ok(GameState { 
-            player: Entity::new_pos(player_texture, player_position, 1),
-            foes: Foes::generate(6, Texture::new(ctx, "./resources/spike.png")?),
-            tile: tile_texture,
-            world: World::new(),
-            ui: UI::new(font2),
-            stats: Stats::new(),
-        })
-    }
-}
-
-impl State for GameState {
-    // draw call
-    fn draw(&mut self, ctx: &mut Context) -> tetra::Result {
-        graphics::clear(ctx, Color::rgb(0.220, 0.220, 0.220));
-
-        for x in 0..BOARD_WIDTH{
-            for y in 0..BOARD_HEIGHT{
-                let tile = self.world.tiles[x][y] as WorldTile;
-                let mut c = Color::BLACK;
-                if tile.passable {
-                    c = Color::WHITE;
-                }
-                self.tile.draw(ctx, DrawParams{
-                    position: Vec2::new(x as f32*33.0,y as f32*33.0),
-                    scale: Vec2::new(1.0,1.0),
-                    origin: Vec2::new(0.0,0.0),
-                    rotation: 0.0,
-                    color: c,
-                })
-            }   
-        }
-
-        self.player.draw(ctx);
-
-        let ids: Vec<&u32> = self.foes.list.keys().collect();
-        for id in &ids{
-            self.foes.list[id].draw(ctx);
-        }
-        self.ui.updateStats(ctx, self.stats);
-        self.ui.updateEvents(ctx, "Something happend.");
-
-
-        Ok(())
-    }
-
-    //game loop
-    fn update(&mut self, ctx: &mut Context) -> tetra::Result {
-
-        let mut tick = false;
-        //input
-        if input::is_key_pressed(ctx, Key::A) {
-            if self.world.is_passable(Vec2::new(self.player.position.x-1,self.player.position.y)) {
-                if self.world.is_occupied_by(Vec2::new(self.player.position.x-1,self.player.position.y))>1 {
-                    //collision
-                }
-                else {
-                    self.player.position.x -= 1;
-                }
-                
-                
-            }
-            self.player.transform.scale.x = -1.0;
-            tick = true;
-        }    
-        if input::is_key_pressed(ctx, Key::D) {
-            if self.world.is_passable(Vec2::new(self.player.position.x+1,self.player.position.y)) {
-                self.player.position.x += 1;
-                tick = true;
-            }
-            self.player.transform.scale.x = 1.0;
-        }
-        if input::is_key_pressed(ctx, Key::W) {
-            if self.world.is_passable(Vec2::new(self.player.position.x,self.player.position.y-1)) {
-                self.player.position.y -= 1;
-                tick = true;
-            }
-        }    
-        if input::is_key_pressed(ctx, Key::S) {
-            if self.world.is_passable(Vec2::new(self.player.position.x,self.player.position.y+1)) {
-                self.player.position.y += 1;
-                tick = true;
-            }
-        }
-        if input::is_key_pressed(ctx, Key::Space) {
-            tick = true;
-        }
-
-    
-        // logic
-        if tick{
-
-                
-            let ids: Vec<&u32> = self.foes.list.keys().collect();
-            for id in &ids{
-                // tried To move the logic into the entity, but run into reference ownership issues
-                //self.foes.list[id].update(self);
-                let mut newpos = self.foes.list[id].position;
-                let mut rng = thread_rng();
-                let n:u8 = rng.gen_range(0, 4);
-                match n{
-                    0 => newpos.x += 1,
-                    1 => newpos.x -= 1,
-                    2 => newpos.y += 1,
-                    3 => newpos.y -= 1,
-                    _ => newpos.y -= 0, //impossible to reach, can we avoid this somehow?
-                }
-                if self.world.is_passable(newpos){
-                    // ownership issues
-                    //self.foes.list[id].position = newpos;
-                }
-            }
-        }
-
-        Ok(())
-    }
-}
-
-struct Entity {
-    texture: Texture,
-    transform: DrawParams,
-    position: Vec2<u32>,
-    id: u32,
-}
-
-impl Entity {
-    fn new_pos(texture: Texture, initial_position: Vec2<u32>, id: u32) -> Entity{
-        Entity::with_darwparams(texture, DrawParams{
-            position: Vec2::new(16.0+(initial_position.x as f32) * 33.0, 16.0+(initial_position.y as f32) * 33.0),
-            scale: Vec2::new(1.0,1.0), 
-            origin: Vec2::new(16.0,16.0),
-            rotation: 0.0,
-            color: Color::WHITE, 
-        }, initial_position,
-        id)
-    }
-    fn with_darwparams(texture: Texture, transform: DrawParams, position: Vec2<u32>, id: u32) -> Entity{
-        Entity{
-            texture,
-            transform,
-            position,
-            id,
-        }
-    }
-    fn get_drawparams(&self) -> DrawParams{
-        let mut dp =  self.transform.clone();
-        dp.position= Vec2::new(16.0+(self.position.x as f32) * 33.0, 16.0+(self.position.y as f32) * 33.0);
-        dp
-    }
-    fn update(&self, gs: &GameState ){
-        // let mut newpos = self.position;
-        // let mut rng = thread_rng();
-        // let n:u8 = rng.gen_range(0, 4);
-        // match n{
-        //     0 => newpos.x += 1,
-        //     1 => newpos.x -= 1,
-        //     2 => newpos.y += 1,
-        //     3 => newpos.y -= 1,
-        //     _ => newpos.y -= 0, //impossible to reach, can we avoid this somehow?
-        // }
-        // if gs.world.is_passable(newpos){
-        //     self.position = newpos;
-        // }
-    }
-
-    fn draw(&self, ctx: &mut Context){
-        self.texture.draw(ctx, self.get_drawparams());
-    }
-}
-#[derive(Copy, Clone)]
-struct WorldTile{
-    passable: bool,
-    occupant: u32,
-}
-
-struct World{
-    tiles: [[WorldTile; BOARD_HEIGHT]; BOARD_WIDTH],
-}
-
-impl World{
-    fn new() -> World{
-        let mut new_world: [[WorldTile; BOARD_HEIGHT]; BOARD_WIDTH] = [[WorldTile{passable: false, occupant:0}; BOARD_HEIGHT];BOARD_WIDTH];
-
-        for x in 0..BOARD_WIDTH{
-            for y in 0..BOARD_HEIGHT{
-                if x==0||x==BOARD_WIDTH-1||y==0||y==BOARD_HEIGHT-1 { 
-                    new_world[x][y].passable = false;
-                }
-                else{
-                    let mut rng = thread_rng();
-                    let n:u8 = rng.gen_range(0, 10);
-                    if n<2{
-                        new_world[x][y].passable = false;    
-                    }
-                    else {new_world[x][y].passable = true;}
-                }
-            }   
-        }   
-        World{tiles: new_world}
-    }
-
-    fn is_passable(&self, pos:Vec2<u32>) -> bool{
-        let tile = self.tiles[pos.x as usize][pos.y as usize] as WorldTile;
-        tile.passable
-    }
-    fn is_occupied_by(&self, pos:Vec2<u32>) -> u32{
-        let tile = self.tiles[pos.x as usize][pos.y as usize] as WorldTile;
-        tile.occupant
-    }
-
-}
-
-struct Foes{
-    list: HashMap<u32, Entity>
-}
-
-impl Foes{
-    fn generate(n:u32, texture:Texture) -> Foes{
-        let mut entities = HashMap::new();
-        for i in 2..n{
-            // initial foe position to be calculated here
-            entities.insert(i, Entity::new_pos(texture.clone(),Vec2::new(i,i), i));
-        }
-        Foes{list:entities}
-    }
-}
-
-struct UI{
-    font: Font
-}
-
-impl UI{
-    fn new(font:Font) -> UI{
-        UI{
-            font: font,
-        }
-    }
-    fn updateStats(&mut self, ctx: &mut Context, stats:Stats){
-        let mut health =  Text::new(format!("Health: {}", stats.health), self.font.clone());
-        let mut attack =  Text::new(format!("Attack: {}", stats.attack), self.font.clone());
-        let mut level =  Text::new(format!("Lvl: {}", stats.level), self.font.clone());
-        let mut score =  Text::new(format!("Score: {}", stats.score), self.font.clone());
-        health.draw(ctx, Vec2::new(100.0, 950.0));
-        attack.draw(ctx, Vec2::new(100.0, 970.0));
-        level.draw(ctx, Vec2::new(100.0, 990.0));
-        score.draw(ctx, Vec2::new(100.0, 1010.0));
-    }
-    fn updateEvents(&mut self, ctx: &mut Context, event: &str){
-        let mut event1 =  Text::new(event, self.font.clone());
-        event1.draw(ctx, Vec2::new(500.0, 950.0));
-    }
-}
-
-#[derive(Copy, Clone)]
-struct Stats{
-    health: u32,
-    attack: u32,
-    level: u32,
-    score: u32,
-}
-
-impl Stats{
-    fn new() -> Stats{
-        Stats{
-            health: 100,
-            attack: 10,
-            level: 1,
-            score: 0,
-        }
-    }
-}
\ No newline at end of file