def settings_init args
  # return unless args.tick_count.zero?

  $gtk.notify! "Initializing game", 90 if args.tick_count.zero?

  args.state.bg_color ||= Color::BLACK
  args.state.text_color ||= Color::WHITE
  
  args.state.text_font ||= "fonts/QuinqueFive.ttf"

  args.outputs.background_color = args.state.bg_color

  args.state.transition.last_tick ||= 0
  args.state.transition_bar ||= {left: -256, right: 512}

  args.state.player.w ||= 32
  args.state.player.h ||= 32
  args.state.player.x ||= 128#(1280 / 2) - (args.state.player.w / 2)
  args.state.player.y ||= 128#(720 / 2) - (args.state.player.h / 2)

  args.state.player.start_room ||= {x: 0, y: 0}
  args.state.player.current_room_coordinates ||= {x: 0, y: 0}
  args.state.player.has_sword ||= false
  args.state.player.money_count ||= 0
  args.state.player.bomb_count ||= 0
  args.state.player.bomb_count_max ||= 8

  args.state.maps ||= {}

  args.state.game.show_room_names ||= false
  args.state.game.show_room_links ||= false
  args.state.game.show_tile_coords ||= false

  args.state.hud.weapon_display ||= KeyDisplay.new(args, "F", "")
  args.state.hud.use_item_key_display ||= KeyDisplay.new(args, "A", "")

  args.state.player.rect = {
    x: args.state.player.x + 4,
    y: args.state.player.y + 4,
    w: args.state.player.w - 8,
    h: args.state.player.h - 8,
  }

  args.state.player.move_speed ||= 5
  args.state.player.color ||= Color::GREEN
  args.state.player.show_sword ||= false
  
  args.state.old_room_x ||= 0
  args.state.new_room_x ||= 0
  args.state.old_room_y ||= 0
  args.state.new_room_y ||= 0

  args.state.should_draw_collisions ||= false

  args.state.player.collision_rect = {
    x: args.state.player.x + 4,
    y: args.state.player.y,
    w: 26,
    h: 16
  }

  args.state.player.transition_rects = {
    up: {
      x: args.state.player.x + 12,
      y: (args.state.player.y + 12) + 8,
      w: 8,
      h: 8
    },
    right: {
      x: args.state.player.x + 24,
      y: (args.state.player.y + 10),
      w: 8,
      h: 8
    },
    down: {
      x: args.state.player.x + 12,
      y: (args.state.player.y),
      w: 8,
      h: 8
    },
    left: {
      x: args.state.player.x,
      y: (args.state.player.y) + 10,
      w: 8,
      h: 8
    },
  }

  args.state.current_map ||= "overworld"

  args.state.player.direction ||= :down
  
  args.state.change_worlds ||= false
  args.state.exiting_world ||= false
  args.state.entering_world ||= false
  
  args.state.sword.length ||= 32
  args.state.sword.width ||= 32
  
  args.state.player.attack_length_multiplier ||= 1
  args.state.player.attack_speed ||= 15
  args.state.player.attack_length = args.state.player.attack_speed * args.state.player.attack_length_multiplier
  args.state.player.attack_time ||= 0

  args.state.should_transition ||= false
  args.state.room_transitioning ||= false
  args.state.room_started_trasition ||= false
  args.state.room_trasition_speed = {x: 10, y: 10}

  args.state.room_offset = {x: 384, y: 96}
  args.state.room_width ||= 16*32
  args.state.room_height ||= 11*32
  
  args.state.show_controls_window ||= false

  args.state.room_rect = {
    x: args.state.room_offset.x, y: args.state.room_offset.y,
    w: args.state.room_width, h: args.state.room_height
  }#.merge!(args.state.room_offset)

  if args.state.tick_count.zero?
    args.state.show_debug_rects = false
    args.state.show_debug_info = true
  end

  args.state.room_transition_rect = {
    x: 6, y: 6,
    w: args.state.room_width - 12, h: args.state.room_height - 12
  }

  args.state.draw_scale = 1.0

  args.state.player.inventory ||= Inventory.new(args)
  args.state.player.money_display ||= CapacityDisplay.new(args, "money", "sprites/money/Gem_Green.png", 0)
  args.state.player.bomb_display ||= CapacityDisplay.new(args, "bomb_display", "sprites/item_bomb.png", 0)
  args.state.player.key_display ||= CapacityDisplay.new(args, "key_display", "sprites/tool_key_red.png", 0)
  args.state.player.energy ||= EnergyManager.new(5, 0, 10)

  # args.state.player.energy.add!(1)
  # args.state.inventory_x ||= -96
  # args.state.inventory_state ||= :closed

  args.state.ground_items ||= []
end

def sword_point args
  player = args.state.player
  sword_length = 16
  sword_width = 8
  case player.direction
  when :up
    {x: player.x + (player.w / 2), y: (player.y + player.h)}
  when :down
    {x: player.x + (player.w / 2), y: player.y}
  when :left
    {x: player.x - sword_length, y: player.y + (player.h / 2)}
  when :right
    {x: player.x + player.w, y: player.y + (player.h / 2)}
  end
end

def angle_for_direction direction
  case direction
  when :up
    90
  when :down
    270
  when :left
    180
  when :right
    0
  end
end

def sword_props(args)
  player = args.state.player

  direction = args.state.player.direction
  tip = {x: 0, y: 0, w: 4, h: 4}
  shaft = sword_shaft(args)
  {
    shaft: shaft,
    collision: sword_collision_rect(args, shaft)
  }
end

def sword_shaft(args)
  sword = args.state.sword
  player = args.state.player
  direction = player.direction

  case direction
  when :left, :right
    w = sword.length
    h = sword.width
  when :up, :down
    h = sword.width
    w = sword.length
  end

  dx = case direction
  when :left
    -w + 7
  when :up, :down
    (player.w / 2) - (w / 2)
  when :right
    player.w - 7
  end

  dy = case direction
  when :left, :right
    (player.h / 2) - (h / 2)
  when :up
    (player.h + h) - w -7
  when :down
    (-h * 2) + w + 7
  end

  {
    x: player.x + dx,
    y: player.y + dy,
    w: sword.length,
    h: sword.width,
    angle: angle_for_direction(direction)
  }
end

def sword_collision_rect(args, shaft)
  direction = args.state.player.direction
  rect = case direction
  when :left
    {x: shaft.x, y: shaft.y + 12, w: 20, h: 8}
  when :right
    {x: shaft.x + 12, y: shaft.y + 12, w: 20, h: 8}
  when :up
    {x: shaft.x + 12, y: shaft.y + 12, w: 8, h: 20}
  when :down 
    {x: shaft.x + 12, y: shaft.y + 4, w: 8, h: 20}
  end
end

def process_player_input args
  return unless args.audio[:item_get].nil?
  return unless args.state.player.inventory.is_closed?
  move_speed = args.state.player.move_speed
  if not args.state.player.show_sword
    if args.inputs.keyboard.key_held.left
      args.state.player.direction = :left
      if args.state.player.x - move_speed > 0
        potential_player_pos = args.state.player.collision_rect.copy
        potential_player_pos.x -= move_speed
        args.state.player.x -= move_speed unless check_collisions(args, potential_player_pos)
      end
    end
    if args.inputs.keyboard.key_held.right
      w = args.state.player.w
      args.state.player.direction = :right
      if (args.state.player.x + w) + 10 < args.grid.w
        potential_player_pos = args.state.player.collision_rect
        potential_player_pos.x += move_speed

        args.state.player.x += move_speed unless check_collisions(args, potential_player_pos)
      end
    end
    if args.inputs.keyboard.key_held.up
      args.state.player.direction = :up
      h = args.state.player.h

      if (args.state.player.y + h) + move_speed < args.grid.h
        potential_player_pos = args.state.player.collision_rect
        potential_player_pos.y += move_speed
        args.state.player.y += move_speed unless check_collisions(args, potential_player_pos)
      end
    end
    if args.inputs.keyboard.key_held.down
      args.state.player.direction = :down
      if args.state.player.y - move_speed > 0
        potential_player_pos = args.state.player.collision_rect
        potential_player_pos.y -= move_speed
        args.state.player.y -= move_speed unless check_collisions(args, potential_player_pos)
      end
    end
    if args.inputs.keyboard.key_down.f && args.state.player.has_sword#and args.state.player.attack_time == 0
      args.state.player.show_sword = !args.state.player.show_sword
    end
  end

  check_room_link_collision(args)
  check_interactive_collisions(args)
end

def reset_sword args
  args.state.player.has_sword = false
end

def check_interactive_collisions(args)
  current_room_coordinates = args.state.player.current_room_coordinates
  map = args.state.current_map#args.state.maps[]

  interactives = map.ground_items_at(current_room_coordinates.x, current_room_coordinates.y)

  return if interactives.nil?
  return if interactives.empty?

  #made it to here lets check collisions
  collided_item = interactives.find do | item |
    item.collision_rect.intersect_rect?(args.state.player.collision_rect)
  end

  return if not collided_item

  #ok we found an item now lets check what it is
  case collided_item.name
  when "WoodenSword"
    if !args.state.player.has_sword
      puts "player found wooden sword"
      args.state.player.has_sword = true
      args.audio[:item_get] = { input: "sounds/item_get2.wav" }
      #we should remove the item and play the sound for item get then show that we got the item
      map.remove_ground_item_at(collided_item, current_room_coordinates.x, current_room_coordinates.y)

    end
  end
end

def check_room_link_collision(args)
  current_room_coordinates = args.state.player.current_room_coordinates
  map = args.state.current_map#args.state.maps[]

  links = map.links_for_map(current_room_coordinates.x, current_room_coordinates.y)
  if links and not links.empty?    
    player_rect = args.state.player.collision_rect
    collided_link = links.find do | link |
      link.collision_rect.intersect_rect?(player_rect)
    end

    if collided_link #and not collided_link.empty?
      args.state.transition.link = collided_link
      
      new_map = args.state.maps[collided_link.destination_name]
      destination_coordinates = collided_link.destination_coordinates
      args.state.transition.room_refs = {
        old_room: map.room_at(current_room_coordinates.x, current_room_coordinates.y),
        new_room: new_map.room_at(destination_coordinates.x, destination_coordinates.y)
      }

      link_spawn = new_map.link_spawn_at(destination_coordinates.x, destination_coordinates.y)
      args.state.player.x = link_spawn.x
      args.state.player.y = link_spawn.y

      puts "return room #{args.state.return_room}"
      
      args.state.change_worlds = true
      args.state.transition.start_animation = true
      args.state.transition.exiting = true
      args.state.transition.entering = false
    end
  end
end



def show_energy(args, target, position = {x: 0, y: 0}, fill_percentage = 0)
  draw = {w: 16, h: 16}
  args.outputs[target].w = draw.w
  args.outputs[target].h = draw.h
  args.outputs[target].transient!
  
  output = []

  energy = {
    x: 0, y: 0, w: draw.w, h: draw.h, path: "sprites/energy2.png"
  }
  energy_fill_bg = {
    x: 0, y: 0, **draw, path: :pixel, **Color::RED, blendmode_enum: 2
  }
  energy_fill = {
    x: draw.w / 100 * fill_percentage, y: 0, **draw, path: :pixel, **Color::WHITE, blendmode_enum: 2
  }
  
  output << energy
  output << energy_fill_bg
  output << energy_fill
  
  args.outputs[target].primitives << output
end

def draw_player args
  player = args.state.player
  if player.show_sword
    args.state.player.attack_time += 1
  end
  if args.state.player.attack_time >= args.state.player.attack_length
    args.state.player.attack_time = 0
    args.state.player.show_sword = false
  end

  scale = args.state.draw_scale
  player_gfx = {
    x: player.x,
    y: player.y,
    w: player.w * scale, h: player.h * scale,
    angle: angle_for_direction(player.direction),
    path: "sprites/circle/green.png"
  }.to_sprite


  args.outputs[:buffer].primitives << player_gfx

  if args.state.show_debug_rects
    # debug_rects = [player.transition_rects.up, player.transition_rects.right, player.transition_rects.down, player.transition_rects.left, player.collision_rect]
    debug_rects = [player.collision_rect]
    debug_rects.each do | rect |
      rect.merge!(**Color::RED).merge!({}.to_border)
    end
    args.outputs[:buffer].primitives << debug_rects
  end

  draw_sword args

  if args.state.show_debug_rects
    args.outputs.borders << {**player_gfx, **Color::WHITE}
  end
end


def draw_sword args
  if args.state.player.show_sword
    sword_color = Color::BROWN
    props = sword_props( args)

    sword = [
      props[:shaft].merge({path: "sprites/sword2.png", primitive_marker: :sprite}),
    ]

    args.outputs[:buffer].primitives << sword
  end
end

def draw_world_change_old(args)
  current_room = args.state.player.current_room_coordinates
  if !args.state.exiting_world
    args.state.exiting_world = true
    args.state.left_x = -256
    args.state.right_x = 512
    args.state.slide_speed = 8
    args.state.exiting_world_start = 0
  end

  change_buffer_name = :change_buffer
  create_room_rt(args, change_buffer_name)
  args.state.map.draw(args, change_buffer_name)
  
  if args.state.exiting_world and not args.state.entering_world
    args.state.left_x += args.state.slide_speed if args.state.left_x + args.state.slide_speed <= 0
    args.state.right_x -= args.state.slide_speed if args.state.right_x - args.state.slide_speed >= 256
    if args.state.left_x >= 0 and args.state.exiting_world_start <= 0
      args.state.exiting_world_start = args.state.tick_count
    end
  end
  
  if args.state.exiting_world_start > 0
    tick_diff = args.state.tick_count - args.state.exiting_world_start
    if tick_diff > 15 and args.state.exiting_world and !args.state.mid_transition
      $gtk.notify! "mid transition, change world maps now", 30
      args.state.mid_transition = true
      transition_link = args.state.transition_link
      
      new_map_name = transition_link.destination_name
      new_map = args.state.maps[new_map_name]
      
      destination_coordinates = transition_link.destination_coordinates
      spawn_location = new_map.link_spawn_at(destination_coordinates.x, destination_coordinates.y)
      if spawn_location != nil
        args.state.player.x = spawn_location.x
        args.state.player.y = spawn_location.y
      end
      
      args.state.entering_world = true
      
      set_map(args, transition_link.destination_name)
      
      args.state.player.current_room_coordinates = destination_coordinates.copy
    end
  end

  args.outputs[change_buffer_name].primitives << {x: args.state.left_x, y: 0, w: 256, h: 352, **Color::BLACK, primitive_marker: :sprite}
  args.outputs[change_buffer_name].primitives << {x: args.state.right_x, y: 0, w: 256, h: 352, **Color::BLACK, primitive_marker: :sprite}
  
  if args.state.entering_world and args.state.exiting_world
    args.state.left_x -= args.state.slide_speed if args.state.left_x - args.state.slide_speed >= -256
    args.state.right_x += args.state.slide_speed if args.state.right_x + args.state.slide_speed < 512
    if args.state.left_x <= -256
      draw_room(args)

      args.state.finished_change = true
    end
  end

  args.outputs.primitives << {**args.state.room_offset, w: 512, h: 352, path: change_buffer_name, primitive_marker: :sprite}

  if args.state.finished_change
    args.state.change_worlds = false
    args.state.exiting_world = false
    args.state.entering_world = false
    args.state.finished_change = false
    args.state.left_x = -256
    args.state.right_x = 512
    args.state.exiting_world_start = 0
  end
end