
# TODO: important!!! level templates use the same element_info as the level
# itself. where to store it? we want to be able to have multiple levels open
# (so element_info shouldn't be a global variable), but the data must be
# shared between the level and its level template. (Note: of course, this only
# applies if Level@use_custom_template is set to true, otherwise the template
# isn't used.)

class Level
  struct LevelFileInfo file_info

  attr_accessor :game_engine_type

  # level stored in native format for the alternative native game engines
  struct LevelInfo_EM *native_em_level # TODO: determine if needed

  attr_accessor :file_version # file format version the level is stored with
  attr_accessor :game_version # game release version the level was created with

  attr_bool :encoding_16bit_field     # level contains 16-bit elements
  attr_bool :encoding_16bit_yamyam    # yamyam contains 16-bit elements
  attr_bool :encoding_16bit_amoeba    # amoeba contains 16-bit elements

  attr_accessor :fieldx, :fieldy

  attr_accessor :time             # available time (seconds)
  attr_accessor :gems_needed

  attr_accessor :name
  attr_accessor :author

  attr_accessor :envelope_text
  attr_accessor :envelope_xsize, :envelope_ysize

  attr_accessor :score

  attr_accessor :yamyam_content
  attr_accessor :num_yamyam_contents

  attr_accessor :amoeba_speed
  attr_accessor :amoeba_content

  attr_accessor :time_magic_wall
  attr_accessor :time_wheel
  attr_accessor :time_light
  attr_accessor :time_timegate

  # values for the new EMC elements
  attr_accessor :android_move_time
  attr_accessor :android_clone_time
  attr_bool :ball_random
  attr_bool :ball_state_initial
  attr_accessor :ball_time
  attr_accessor :lenses_score
  attr_accessor :magnify_score
  attr_accessor :slurp_score
  attr_accessor :lenses_time
  attr_accessor :magnify_time
  attr_accessor :wind_direction_initial
  attr_accessor :ball_content[NUM_MAGIC_BALL_CONTENTS][3][3]
  attr_bool :android_array[16]

  attr_accessor :can_move_into_acid_bits  # bitfield to store property for elements
  attr_accessor :dont_collide_with_bits   # bitfield to store property for elements

  attr_bool :double_speed
  attr_bool :initial_gravity
  attr_bool :em_slippery_gems # EM style "gems slip from wall" behaviour
  attr_bool :use_spring_bug   # for compatibility with old levels
  attr_bool :instant_relocation   # no visual delay when relocating player
  attr_bool :can_pass_to_walkable # player can pass to empty or walkable tile
  attr_bool :grow_into_diggable   # amoeba can grow into anything diggable

  attr_bool :block_last_field # player blocks previous field while moving
  attr_bool :sp_block_last_field  # player blocks previous field while moving


  # ('attr_accessor' instead of 'attr_bool' because used as selectbox value in editor)
  attr_accessor :use_step_counter     # count steps instead of seconds for level

  attr_accessor :field

  attr_bool :use_custom_template  # use custom properties from template file

  attr_bool :no_valid_file    # set when level file missing or invalid

  attr_bool :changed      # set when level was changed in the editor
  
  @@_clipboard_elements_initialized = false
  
  def initialize
    setLevelInfoToDefaults_EM()

    @native_em_level = &native_em_level

    @game_engine_type = GAME_ENGINE_TYPE_RND

    @file_version = FILE_VERSION_ACTUAL
    @game_version = GAME_VERSION_ACTUAL

    @encoding_16bit_field  = false # default: only 8-bit elements
    @encoding_16bit_yamyam = false # default: only 8-bit elements
    @encoding_16bit_amoeba = false # default: only 8-bit elements

    @fieldx = STD_LEV_FIELDX
    @fieldy = STD_LEV_FIELDY

    @field = Misc.array(MAX_LEV_FIELDX, MAX_LEV_FIELDY, EL_SAND)

    @time = 100
    @gems_needed = 0

    @amoeba_speed = 10

    @time_magic_wall = 10
    @time_wheel = 10
    @time_light = 10
    @time_timegate = 10

    @amoeba_content = EL_DIAMOND

    @double_speed = false
    @initial_gravity = false
    @em_slippery_gems = false
    @instant_relocation = false
    @can_pass_to_walkable = false
    @grow_into_diggable = true

    @block_last_field = false  # EM does not block by default
    @sp_block_last_field = true    # SP blocks the last field

    @can_move_into_acid_bits = ~0  # everything can move into acid
    @dont_collide_with_bits = ~0   # always deadly when colliding

    @use_spring_bug = false
    @use_step_counter = false

    # values for the new EMC elements
    @android_move_time = 10
    @android_clone_time = 10
    @ball_random = false
    @ball_state_initial = false
    @ball_time = 10
    @lenses_score = 10
    @magnify_score = 10
    @slurp_score = 10
    @lenses_time = 10
    @magnify_time = 10
    @wind_direction_initial = MV_NO_MOVING
    @ball_content = Misc.array(NUM_MAGIC_BALL_CONTENTS, 3, 3, EL_EMPTY)
    @android_array = Array.new(16, false)

    @use_custom_template = false

    @name = NAMELESS_LEVEL_NAME
    @author = ANONYMOUS_NAME

    @envelope_text = Array.new(4, "")
    @envelope_xsize = Array.new(4, MAX_ENVELOPE_XSIZE)
    @envelope_ysize = Array.new(4, MAX_ENVELOPE_YSIZE)

    @score = Array.new(LEVEL_SCORE_ELEMENTS, 10)

    @num_yamyam_contents = STD_ELEMENT_CONTENTS
    arr = []
    MAX_ELEMENT_CONTENTS.times do |i|
      arr.push(Misc.array(3, 3, (i < STD_ELEMENT_CONTENTS ? EL_ROCK : EL_EMPTY))
    end
    @yamyam_content = arr

    @field[0][0] = EL_PLAYER_1
    @field[@fieldx-1][@fieldy-1] = EL_EXIT_CLOSED

    MAX_NUM_ELEMENTS.times { |eid|
      element = element_info[eid]

      # initialize clipboard elements only once
      next if IS_CLIPBOARD_ELEMENT(eid) && @@clipboard_elements_initialized

      element.numChangePages = 1 # TODO: maybe element_info[element] isn't yet initialized?
      
      if IS_CUSTOM_ELEMENT(eid) || IS_GROUP_ELEMENT(eid) || IS_INTERNAL_ELEMENT(eid)
        element.description = ""

        if element.custom_description
          element.description = element.custom_description
        else
          element.description = element.editor_description
        end

        element.use_gfx_element = false
        element.gfx_element = EL_EMPTY_SPACE

        element.modified_settings = false
      end

      if IS_CUSTOM_ELEMENT(eid) || IS_INTERNAL_ELEMENT(eid)
        element.access_direction = MV_ALL_DIRECTIONS

        element.collect_score = 10     # special default
        element.collect_count = 1      # special default

        element.push_delay_fixed = -1  # initialize later
        element.push_delay_random = -1 # initialize later
        element.drop_delay_fixed = 0
        element.drop_delay_random = 0
        element.move_delay_fixed = 0
        element.move_delay_random = 0

        element.move_pattern = MV_ALL_DIRECTIONS
        element.move_direction_initial = MV_START_AUTOMATIC
        element.move_stepsize = TILEX / 8

        element.move_enter_element = EL_EMPTY_SPACE
        element.move_leave_element = EL_EMPTY_SPACE
        element.move_leave_type = LEAVE_TYPE_UNLIMITED

        element.slippery_type = SLIPPERY_ANY_RANDOM

        element.explosion_type = EXPLODES_3X3
        element.explosion_delay = 16
        element.ignition_delay = 8

        element.content = Misc.array(3,3,EL_EMPTY_SPACE)

        element.access_type = 0
        element.access_layer = 0
        element.access_protected = 0
        element.walk_to_action = 0
        element.smash_targets = 0
        element.deadliness = 0

        element.can_explode_by_fire = false
        element.can_explode_smashed = false
        element.can_explode_impact = false

        element.current_change_page = 0

        # start with no properties at all
        NUM_EP_BITFIELDS.times { |i| Properties[eid][i] = EP_BITMASK_DEFAULT }

        # now set default properties
        SET_PROPERTY(eid, EP_CAN_MOVE_INTO_ACID, true)
      end

      if IS_GROUP_ELEMENT(eid) || IS_INTERNAL_ELEMENT(eid)
        # initialize memory for list of elements in group
        if (element.group == nil)
          element.group = ElementGroupInfo.new

        MAX_ELEMENTS_IN_GROUP.times { |i| element.group.elements[i] = EL_EMPTY_SPACE }

        # default: only one element in group
        element.group.num_elements = 1

        element.group.choice_mode = ANIM_RANDOM
      end
    }

    @@clipboard_elements_initialized = true

    BorderElement = EL_STEELWALL # TODO: determine what type of var is BorderElement

    @no_valid_file = false

    @changed = false

    return if leveldir_current == NULL     # only when dumping level

    # try to determine better author name than 'anonymous'
    if leveldir_current->author != ANONYMOUS_NAME
      @author = leveldir_current->author
    else
      case LEVELCLASS(leveldir_current)
        when LEVELCLASS_TUTORIAL
          @author = PROGRAM_AUTHOR_STRING
        when LEVELCLASS_CONTRIB
          @author = leveldir_current->name
        when LEVELCLASS_PRIVATE
          @author = getRealName
      end
    end
  end
end
