aboutsummaryrefslogblamecommitdiffstats
path: root/Game/Code/Classes/UIni.pas
blob: 232021b6d9e9e59f21762000ecb673bd64577dc4 (plain) (tree)
1
2
3
4
5
6
7
8
9
10









                  




            





                                            
                                          



               

















































































                                                                                                       








                                   































































                                                                                                                              














































































































































                                                                                                      
 
















































                                                                                                   








                               

                                   









                                                          

                                                

                                    
                                      
           
                                            

        



                                                    































































                                                                                                               























                                                                                                                          




                                                                    

                                                                                       











































































                                                                                                                    
                                                                    



























































































                                                                                       
                               


























































































































































































                                                                                                        
                                 

















































































                                                                                        
unit UIni;

interface

{$IFDEF FPC}
  {$MODE Delphi}
{$ENDIF}

{$I switches.inc}

uses
  Classes,
  IniFiles,
  ULog,
  SysUtils;

type
  PInputDeviceConfig = ^TInputDeviceConfig;
  TInputDeviceConfig = record
    Name:               string;
    Input:              integer;
    ChannelToPlayerMap: array of integer;
  end;

type
  TIni = class
    private
      function ExtractKeyIndex(const key: string; const prefix: string; suffix: string): integer;
      function GetMaxKeyIndex(keys: TStringList; const prefix: string; const suffix: string): integer;
      procedure LoadInputDeviceCfg(IniFile: TMemIniFile);
      procedure SaveInputDeviceCfg(IniFile: TIniFile);
    public
      Name:           array[0..11] of string;

      // Templates for Names Mod
      NameTeam:       array[0..2] of string;
      NameTemplate:   array[0..11] of string;

      //Filename of the opened iniFile
      Filename:       string;

      // Game
      Players:        integer;
      Difficulty:     integer;
      Language:       integer;
      Tabs:           integer;
      Tabs_at_startup:integer; //Tabs at Startup fix
      Sorting:        integer;
      Debug:          integer;

      // Graphics
      Screens:        integer;
      Resolution:     integer;
      Depth:          integer;
      FullScreen:     integer;
      TextureSize:    integer;
      SingWindow:     integer;
      Oscilloscope:   integer;
      Spectrum:       integer;
      Spectrograph:   integer;
      MovieSize:      integer;

      // Sound
      MicBoost:       integer;
      ClickAssist:    integer;
      BeatClick:      integer;
      SavePlayback:   integer;
      Threshold:      integer;

      //Song Preview
      PreviewVolume: integer;
      PreviewFading: integer;

      // Lyrics
      LyricsFont:     integer;
      LyricsEffect:   integer;
      Solmization:    integer;

      // Themes
      Theme:          integer;
      SkinNo:           integer;
      Color:          integer;

      // Record
      InputDeviceConfig: array of TInputDeviceConfig;

      // Advanced
      LoadAnimation:  integer;
      EffectSing:     integer;
      ScreenFade:     integer;
      AskbeforeDel:   integer;
      OnSongClick:    integer;
      LineBonus:      integer;
      PartyPopup:     integer;

      // Controller
      Joypad:         integer;

      // Soundcards
      SoundCard:      array[0..7, 1..2] of integer;

      // Devices
      LPT:            integer;

      procedure Load();
      procedure Save();
      procedure SaveNames;
      procedure SaveLevel;
  end;


var
  Ini:    TIni;
  IResolution:    array of string;
  ILanguage:      array of string;
  ITheme:         array of string;
  ISkin:          array of string;

const
  IPlayers:       array[0..4] of string = ('1', '2', '3', '4', '6');
  IDifficulty:    array[0..2] of string = ('Easy', 'Medium', 'Hard');
  ITabs:          array[0..1] of string = ('Off', 'On');

  ISorting:       array[0..7] of string = ('Edition', 'Genre', 'Language', 'Folder', 'Title', 'Artist', 'Title2', 'Artist2');
  sEdition = 0;
  sGenre = 1;
  sLanguage = 2;
  sFolder = 3;
  sTitle = 4;
  sArtist = 5;
  sTitle2 = 6;
  sArtist2 = 7;

  IDebug:         array[0..1] of string = ('Off', 'On');

  IScreens:       array[0..1] of string = ('1', '2');
  IFullScreen:    array[0..1] of string = ('Off', 'On');
  IDepth:         array[0..1] of string = ('16 bit', '32 bit');
  ITextureSize:   array[0..2] of string = ('128', '256', '512');
  ISingWindow:    array[0..1] of string = ('Small', 'Big');

  //SingBar Mod
  IOscilloscope:  array[0..2] of string = ('Off', 'Osci', 'Bar');
  //IOscilloscope:  array[0..1] of string = ('Off', 'On');

  ISpectrum:      array[0..1] of string = ('Off', 'On');
  ISpectrograph:  array[0..1] of string = ('Off', 'On');
  IMovieSize:     array[0..2] of string = ('Half', 'Full [Vid]', 'Full [BG+Vid]');

  IMicBoost:      array[0..3] of string = ('Off', '+6dB', '+12dB', '+18dB');
  IClickAssist:   array[0..1] of string = ('Off', 'On');
  IBeatClick:     array[0..1] of string = ('Off', 'On');
  ISavePlayback:  array[0..1] of string = ('Off', 'On');
  IThreshold:     array[0..3] of string = ('5%', '10%', '15%', '20%');
  //Song Preview
  IPreviewVolume: array[0..10] of string = ('Off', '10%', '20%', '30%', '40%', '50%', '60%', '70%', '80%', '90%', '100%');
  IPreviewFading: array[0..5] of string  = ('Off', '1 Sec', '2 Secs', '3 Secs', '4 Secs', '5 Secs');


  ILyricsFont:    array[0..2] of string = ('Plain', 'OLine1', 'OLine2');
  ILyricsEffect:  array[0..3] of string = ('Simple', 'Zoom', 'Slide', 'Ball');
  ISolmization:   array[0..3] of string = ('Off', 'Euro', 'Jap', 'American');

  IColor:         array[0..8] of string = ('Blue', 'Green', 'Pink', 'Red', 'Violet', 'Orange', 'Yellow', 'Brown', 'Black');

  // Advanced
  ILoadAnimation: array[0..1] of string = ('Off', 'On');
  IEffectSing:    array[0..1] of string = ('Off', 'On');
  IScreenFade: array [0..1] of String =('Off', 'On');
  IAskbeforeDel:  array[0..1] of string = ('Off', 'On');
  IOnSongClick:   array[0..2] of string = ('Sing', 'Select Players', 'Open Menu');
  ILineBonus:  array[0..2] of string = ('Off', 'At Score', 'At Notes');
  IPartyPopup: array[0..1] of string = ('Off', 'On');

  IJoypad:        array[0..1] of string = ('Off', 'On');
  ILPT:           array[0..2] of string = ('Off', 'LCD', 'Lights');

  IChannel:       array[0..6] of string = ('Off', '1', '2', '3', '4', '5', '6');

implementation

uses
  StrUtils,
  //UFiles,
  UMain,
  SDL,
  ULanguage,
  UPlatform,
  USkins,
  URecord,
  UCommandLine;

function TIni.ExtractKeyIndex(const key: string; const prefix: string; suffix: string): integer;
var
  tmpStr: string;
begin
  Result := -1;
  if not AnsiStartsText(prefix, key) then
    Exit;
  tmpStr := AnsiReplaceText(key, prefix, '');
  tmpStr := AnsiReplaceText(tmpStr, suffix, '');
  Result := StrToIntDef(tmpStr, -1);
end;

function TIni.GetMaxKeyIndex(keys: TStringList; const prefix: string; const suffix: string): integer;
var
  i: integer;
  keyIndex: integer;
begin
  Result := -1;
  for i := 0 to keys.Count-1 do
  begin
    keyIndex := ExtractKeyIndex(keys[i], prefix, suffix);
    if (keyIndex > Result) then
      Result := keyIndex;
  end;
end;

procedure TIni.LoadInputDeviceCfg(IniFile: TMemIniFile);
var
  deviceIndex: integer;
  deviceCfgIndex: integer;
  deviceCfg: PInputDeviceConfig;
  device: TAudioInputDevice;
  deviceIniIndex: integer;
  deviceIniStr: string;
  channelCount: integer;
  channelIndex: integer;
  channelIndexStr: string;
  newDevice: boolean;
  recordKeys: TStringList;
  i: integer;
begin
  recordKeys := TStringList.Create();

  // read all record-keys for filtering
  IniFile.ReadSection('Record', recordKeys);

  deviceCfgIndex := 0;
  SetLength(InputDeviceConfig, 0);

  for i := 0 to recordKeys.Count-1 do
  begin
    // find next device-name
    deviceIniIndex := ExtractKeyIndex(recordKeys[i], 'DeviceName[', ']');
    if (deviceIniIndex < 0) then
      continue;
    deviceIniStr := IntToStr(deviceIniIndex);

    if not IniFile.ValueExists('Record', 'DeviceName['+deviceIniStr+']') then
      break;

    // resize list
    SetLength(InputDeviceConfig, deviceCfgIndex+1);

    deviceCfg := @InputDeviceConfig[deviceCfgIndex];

    // read an input device's config.
    // Note: All devices are appended to the list whether they exist or not.
    //   Otherwise an external device's config will be lost if it is not
    //   connected (e.g. singstar mics or USB-Audio devices).
    deviceCfg.Name := IniFile.ReadString('Record', 'DeviceName['+deviceIniStr+']', '');
    deviceCfg.Input := IniFile.ReadInteger('Record', 'Input['+deviceIniStr+']', 0);

    // find the largest channel-number of the current device in the ini-file
    channelCount := GetMaxKeyIndex(recordKeys, 'Channel(', ')['+deviceIniStr+']');
    if (channelCount < 0) then
      channelCount := 0;

    SetLength(deviceCfg.ChannelToPlayerMap, channelCount);

    // read channel-to-player mapping for every channel of the current device
    // or set non-configured channels to no player (=0).
    for channelIndex := 0 to High(deviceCfg.ChannelToPlayerMap) do
    begin
      channelIndexStr := IntToStr(channelIndex+1);
      deviceCfg.ChannelToPlayerMap[channelIndex] :=
        IniFile.ReadInteger('Record', 'Channel('+channelIndexStr+')['+deviceIniStr+']', 0);
    end;

    Inc(deviceCfgIndex);
  end;

  recordKeys.Free();

  // Input devices - append detected soundcards
  for deviceIndex := 0 to High(AudioInputProcessor.Device) do
  begin
    newDevice := true;
    for deviceCfgIndex := 0 to High(InputDeviceConfig) do
    begin //Search for Card in List
      deviceCfg := @InputDeviceConfig[deviceCfgIndex];
      device := AudioInputProcessor.Device[deviceIndex];

      if (deviceCfg.Name = Trim(device.Description)) then
      begin
        newDevice := false;

        // store highest channel index as an offset for the new channels
        channelIndex := High(deviceCfg.ChannelToPlayerMap);
        // add missing channels or remove non-existing ones
        SetLength(deviceCfg.ChannelToPlayerMap, device.AudioFormat.Channels);
        // initialize added channels to 0
        for i := channelIndex+1 to High(deviceCfg.ChannelToPlayerMap) do
        begin
          deviceCfg.ChannelToPlayerMap[i] := 0;
        end;

        // associate ini-index with device
        device.CfgIndex := deviceCfgIndex;

        Break;
      end;
    end;

    //If not in List -> Add
    if newDevice then
    begin
      // resize list
      SetLength(InputDeviceConfig, Length(InputDeviceConfig)+1);
      deviceCfgIndex := High(InputDeviceConfig);

      deviceCfg := @InputDeviceConfig[deviceCfgIndex];
      device := AudioInputProcessor.Device[deviceIndex];

      deviceCfg.Name := Trim(AudioInputProcessor.Device[deviceIndex].Description);
      deviceCfg.Input := 0;

      channelCount := device.AudioFormat.Channels;
      SetLength(deviceCfg.ChannelToPlayerMap, channelCount);

      for channelIndex := 0 to channelCount-1 do
      begin
        // set default at first start of USDX (1st device, 1st channel -> player1)
        if ((channelIndex = 0) and (deviceCfgIndex = 0)) then
          deviceCfg.ChannelToPlayerMap[0] := 1
        else
          deviceCfg.ChannelToPlayerMap[channelIndex] := 0;
      end;

      // associate ini-index with device
      device.CfgIndex := deviceCfgIndex;
    end;
  end;

end;

procedure TIni.SaveInputDeviceCfg(IniFile: TIniFile);
var
  deviceIndex: integer;
  deviceIndexStr: string;
  channelIndex: integer;
  channelIndexStr: string;
  valueStr: string;
begin
  for deviceIndex := 0 to High(InputDeviceConfig) do begin
    deviceIndexStr := IntToStr(deviceIndex+1);

    valueStr := InputDeviceConfig[deviceIndex].Name;
    IniFile.WriteString('Record', 'DeviceName['+deviceIndexStr+']', valueStr);

    valueStr := IntToStr(InputDeviceConfig[deviceIndex].Input);
    IniFile.WriteString('Record', 'Input['+deviceIndexStr+']', valueStr);

    for channelIndex := 0 to High(InputDeviceConfig[deviceIndex].ChannelToPlayerMap) do
    begin
      channelIndexStr := IntToStr(channelIndex+1);
      valueStr := IntToStr(InputDeviceConfig[deviceIndex].ChannelToPlayerMap[channelIndex]);
      IniFile.WriteString('Record', 'Channel('+channelIndexStr+')['+deviceIndexStr+']', valueStr);
    end;
  end;
end;

procedure TIni.Load();
var
  IniFile:    TMemIniFile;
  ThemeIni:   TMemIniFile;
  Tekst:      string;
  Pet:        integer;
  B: boolean;
  I, I2, I3:          integer;
  S:          string;
  Modes:      PPSDL_Rect;
  SR: TSearchRec; //Skin List Patch
  lFileName : String;

  function GetFileName (S: String):String;
  begin
  //Result := copy (S,0,StrRScan (PChar(S),char('.'))+1);
    Result := copy (S,0,Pos ('.ini',S)-1);
  end;

begin
  GamePath := Platform.GetGameUserPath;

  Log.LogStatus( 'GamePath : ' +GamePath , '' );

  if (Params.ConfigFile <> '') then
    try
      lFileName := Params.ConfigFile;
    except
      lFileName := GamePath + 'config.ini';
    end
  else
    lFileName := GamePath + 'config.ini';

  Log.LogStatus( 'Using config : ' +lFileName , '');
  IniFile := TMemIniFile.Create( lFileName );


  // Name
  for I := 0 to 11 do
    Ini.Name[I] := IniFile.ReadString('Name', 'P'+IntToStr(I+1), 'Player'+IntToStr(I+1));


  // Templates for Names Mod
  for I := 0 to 2 do
    Ini.NameTeam[I] := IniFile.ReadString('NameTeam', 'T'+IntToStr(I+1), 'Team'+IntToStr(I+1));
  for I := 0 to 11 do
    Ini.NameTemplate[I] := IniFile.ReadString('NameTemplate', 'Name'+IntToStr(I+1), 'Template'+IntToStr(I+1));

  // Players
  Tekst := IniFile.ReadString('Game', 'Players', IPlayers[0]);
  for Pet := 0 to High(IPlayers) do
    if Tekst = IPlayers[Pet] then Ini.Players := Pet;

  // Difficulty
  Tekst := IniFile.ReadString('Game', 'Difficulty', 'Easy');
  for Pet := 0 to High(IDifficulty) do
    if Tekst = IDifficulty[Pet] then Ini.Difficulty := Pet;

  // Language
  Tekst := IniFile.ReadString('Game', 'Language', 'English');
  for Pet := 0 to High(ILanguage) do
    if Tekst = ILanguage[Pet] then Ini.Language := Pet;

//  Language.ChangeLanguage(ILanguage[Ini.Language]);

  // Tabs
  Tekst := IniFile.ReadString('Game', 'Tabs', ITabs[0]);
  for Pet := 0 to High(ITabs) do
    if Tekst = ITabs[Pet] then Ini.Tabs := Pet;

  //Tabs at Startup fix
  Ini.Tabs_at_startup := Ini.Tabs;

  // Sorting
  Tekst := IniFile.ReadString('Game', 'Sorting', ISorting[0]);
  for Pet := 0 to High(ISorting) do
    if Tekst = ISorting[Pet] then Ini.Sorting := Pet;

  // Debug
  Tekst := IniFile.ReadString('Game', 'Debug', IDebug[0]);
  for Pet := 0 to High(IDebug) do
    if Tekst = IDebug[Pet] then Ini.Debug := Pet;

  //if Ini.Debug = 1 then SongPath := 'E:\UltraStar 03\Songs\';

  // Screens
  Tekst := IniFile.ReadString('Graphics', 'Screens', IScreens[0]);
  for Pet := 0 to High(IScreens) do
    if Tekst = IScreens[Pet] then Ini.Screens := Pet;

  // FullScreen
  Tekst := IniFile.ReadString('Graphics', 'FullScreen', 'On');
  for Pet := 0 to High(IFullScreen) do
    if Tekst = IFullScreen[Pet] then Ini.FullScreen := Pet;


  // Resolution
  SetLength(IResolution, 0);

  Modes  := SDL_ListModes(nil, SDL_OPENGL or SDL_RESIZABLE ) ; // Check if there are any modes available
//  Modes  := SDL_ListModes(nil, SDL_OPENGL or SDL_FULLSCREEN or SDL_RESIZABLE); // Check if there are any modes available
  if integer( Modes ) = 0 then
  begin
    Log.LogStatus( 'No resolutions Found' , 'Video');
  end
  else
  if integer( Modes ) = -1 then
  begin
    Log.LogStatus( 'ANY resolutions can be used' , 'Video');
    // Interesting bug here on linux ...
    // https://bugs.launchpad.net/ubuntu/+source/libsdl1.2/+bug/14044
  end
  else
  begin
    while assigned( Modes^ ) do //this should solve the biggest wine problem | THANKS Linnex (11.11.07)
    begin
      Log.LogStatus( 'Found Video Mode : ' + IntToStr(Modes^.w) + 'x' + IntToStr(Modes^.h) , 'Video');
      SetLength(IResolution, Length(IResolution) + 1);
      IResolution[High(IResolution)] := IntToStr(Modes^.w) + 'x' + IntToStr(Modes^.h);
      Inc(Modes);
    end;
  end;
 

  // if no modes were set, then failback to 800x600
  // as per http://sourceforge.net/forum/message.php?msg_id=4544965
  // THANKS : linnex at users.sourceforge.net
  if Length(IResolution) < 1 then
  begin
    Log.LogStatus( 'Found Video Mode : NONE !!! ( Defaulted to 800 x 600 )', 'Video');
    SetLength(IResolution, Length(IResolution) + 1);
    IResolution[High(IResolution)] := IntToStr(800) + 'x' + IntToStr(600);
    Log.LogStatus('SDL_ListModes Defaulted Res To : ' + IResolution[High(IResolution)] , 'Graphics - Resolutions');

    // Default to fullscreen OFF, in this case !
    Ini.FullScreen := 0;
  end;

  // reverse order
  for I := 0 to (Length(IResolution) div 2) - 1 do begin
    S := IResolution[I];
    IResolution[I] := IResolution[High(IResolution)-I];
    IResolution[High(IResolution)-I] := S;
  end;

  Tekst := IniFile.ReadString('Graphics', 'Resolution', '800x600');
  for Pet := 0 to High(IResolution) do
    if Tekst = IResolution[Pet] then Ini.Resolution := Pet;


  // Resolution
  Tekst := IniFile.ReadString('Graphics', 'Depth', '32 bit');
  for Pet := 0 to High(IDepth) do
    if Tekst = IDepth[Pet] then Ini.Depth := Pet;

  // Texture Size
  Tekst := IniFile.ReadString('Graphics', 'TextureSize', ITextureSize[1]);
  for Pet := 0 to High(ITextureSize) do
    if Tekst = ITextureSize[Pet] then Ini.TextureSize := Pet;

  // SingWindow
  Tekst := IniFile.ReadString('Graphics', 'SingWindow', 'Big');
  for Pet := 0 to High(ISingWindow) do
    if Tekst = ISingWindow[Pet] then Ini.SingWindow := Pet;

  // Oscilloscope
  Tekst := IniFile.ReadString('Graphics', 'Oscilloscope', 'Bar');
  for Pet := 0 to High(IOscilloscope) do
    if Tekst = IOscilloscope[Pet] then Ini.Oscilloscope := Pet;

  // Spectrum
  Tekst := IniFile.ReadString('Graphics', 'Spectrum', 'Off');
  for Pet := 0 to High(ISpectrum) do
    if Tekst = ISpectrum[Pet] then Ini.Spectrum := Pet;

  // Spectrograph
  Tekst := IniFile.ReadString('Graphics', 'Spectrograph', 'Off');
  for Pet := 0 to High(ISpectrograph) do
    if Tekst = ISpectrograph[Pet] then Ini.Spectrograph := Pet;

  // MovieSize
  Tekst := IniFile.ReadString('Graphics', 'MovieSize', IMovieSize[2]);
  for Pet := 0 to High(IMovieSize) do
    if Tekst = IMovieSize[Pet] then Ini.MovieSize := Pet;

  // MicBoost
  Tekst := IniFile.ReadString('Sound',    'MicBoost',    'Off');
  for Pet := 0 to High(IMicBoost) do
    if Tekst = IMicBoost[Pet] then Ini.MicBoost := Pet;

  // ClickAssist
  Tekst := IniFile.ReadString('Sound',    'ClickAssist', 'Off');
  for Pet := 0 to High(IClickAssist) do
    if Tekst = IClickAssist[Pet] then Ini.ClickAssist := Pet;

  // BeatClick
  Tekst := IniFile.ReadString('Sound',    'BeatClick', IBeatClick[0]);
  for Pet := 0 to High(IBeatClick) do
    if Tekst = IBeatClick[Pet] then Ini.BeatClick := Pet;

  // SavePlayback
  Tekst := IniFile.ReadString('Sound',    'SavePlayback', ISavePlayback[0]);
  for Pet := 0 to High(ISavePlayback) do
    if Tekst = ISavePlayback[Pet] then Ini.SavePlayback := Pet;

  // Threshold
  Tekst := IniFile.ReadString('Sound', 'Threshold', IThreshold[1]);
  for Pet := 0 to High(IThreshold) do
    if Tekst = IThreshold[Pet] then Ini.Threshold := Pet;

  //Song Preview
  Tekst := IniFile.ReadString('Sound', 'PreviewVolume', IPreviewVolume[7]);
  for Pet := 0 to High(IPreviewVolume) do
    if Tekst = IPreviewVolume[Pet] then Ini.PreviewVolume := Pet;

  Tekst := IniFile.ReadString('Sound', 'PreviewFading', IPreviewFading[1]);
  for Pet := 0 to High(IPreviewFading) do
    if Tekst = IPreviewFading[Pet] then Ini.PreviewFading := Pet;

  // Lyrics Font
  Tekst := IniFile.ReadString('Lyrics',    'LyricsFont',   ILyricsFont[1]);
  for Pet := 0 to High(ILyricsFont) do
    if Tekst = ILyricsFont[Pet] then Ini.LyricsFont := Pet;

  // Lyrics Effect
  Tekst := IniFile.ReadString('Lyrics',    'LyricsEffect',   ILyricsEffect[1]);
  for Pet := 0 to High(ILyricsEffect) do
    if Tekst = ILyricsEffect[Pet] then Ini.LyricsEffect := Pet;

  // Solmization
  Tekst := IniFile.ReadString('Lyrics',    'Solmization',   ISolmization[0]);
  for Pet := 0 to High(ISolmization) do
    if Tekst = ISolmization[Pet] then Ini.Solmization := Pet;

  // Theme

  //Theme List Patch

    //I2 Saves the no of the Deluxe (Standard-) Theme
    I2 := 0;
    //I counts is the cur. Theme no
    I := 0;

    SetLength(ITheme, 0);
    writeln( 'Searching for Theme : '+ ThemePath + '*.ini' );
    FindFirst(ThemePath + '*.ini',faAnyFile,SR);
    Repeat
      writeln( SR.Name );

      //Read Themename from Theme
      ThemeIni := TMemIniFile.Create(SR.Name);
      Tekst    := UpperCase(ThemeIni.ReadString('Theme','Name',GetFileName(SR.Name)));
      ThemeIni.Free;

      //if Deluxe Theme then save Themeno to I2
      if (Tekst = 'DELUXE') then
        I2 := I;

      //Search for Skins for this Theme
      for Pet := low(Skin.Skin) to high(Skin.Skin) do
      begin
        if UpperCase(Skin.Skin[Pet].Theme) = Tekst then
        begin
          SetLength(ITheme, Length(ITheme)+1);
          ITheme[High(ITheme)] := GetFileName(SR.Name);
          break;
        end;
      end;

      Inc(I);
    Until FindNext(SR) <> 0;
    FindClose(SR);
  //Theme List Patch End }

  //No Theme Found
  if (Length(ITheme)=0) then
  begin
    Log.CriticalError('Could not find any valid Themes.');
  end;


  Tekst := IniFile.ReadString('Themes',    'Theme',   ITheme[I2]);
  Ini.Theme := 0;
  for Pet := 0 to High(ITheme) do
    if Uppercase(Tekst) = Uppercase(ITheme[Pet]) then Ini.Theme := Pet;

  // Skin
  Skin.onThemeChange;
  Ini.SkinNo := 0;

  Tekst := IniFile.ReadString('Themes',    'Skin',   ISkin[0]);
  for Pet := 0 to High(ISkin) do
    if Tekst = ISkin[Pet] then Ini.SkinNo := Pet;

  // Color
  Tekst := IniFile.ReadString('Themes',    'Color',   IColor[0]);
  for Pet := 0 to High(IColor) do
    if Tekst = IColor[Pet] then Ini.Color := Pet;

  LoadInputDeviceCfg(IniFile);

  //Advanced Settings

  // LoadAnimation
  Tekst := IniFile.ReadString('Advanced', 'LoadAnimation', 'On');
  for Pet := 0 to High(ILoadAnimation) do
    if Tekst = ILoadAnimation[Pet] then Ini.LoadAnimation := Pet;

  // ScreenFade
  Tekst := IniFile.ReadString('Advanced', 'ScreenFade', 'On');
  for Pet := 0 to High(IScreenFade) do
    if Tekst = IScreenFade[Pet] then Ini.ScreenFade := Pet;

  // EffectSing
  Tekst := IniFile.ReadString('Advanced', 'EffectSing', 'On');
  for Pet := 0 to High(IEffectSing) do
    if Tekst = IEffectSing[Pet] then Ini.EffectSing := Pet;

  // AskbeforeDel
  Tekst := IniFile.ReadString('Advanced', 'AskbeforeDel', 'On');
  for Pet := 0 to High(IAskbeforeDel) do
    if Tekst = IAskbeforeDel[Pet] then Ini.AskbeforeDel := Pet;

  // OnSongClick
  Tekst := IniFile.ReadString('Advanced', 'OnSongClick', 'Sing');
  for Pet := 0 to High(IOnSongClick) do
    if Tekst = IOnSongClick[Pet] then Ini.OnSongClick := Pet;

  // Linebonus
  Tekst := IniFile.ReadString('Advanced', 'LineBonus', 'At Score');
  for Pet := 0 to High(ILineBonus) do
    if Tekst = ILineBonus[Pet] then Ini.LineBonus := Pet;

  // PartyPopup
  Tekst := IniFile.ReadString('Advanced', 'PartyPopup', 'On');
  for Pet := 0 to High(IPartyPopup) do
    if Tekst = IPartyPopup[Pet] then Ini.PartyPopup := Pet;


  // Joypad
  Tekst := IniFile.ReadString('Controller',    'Joypad',   IJoypad[0]);
  for Pet := 0 to High(IJoypad) do
    if Tekst = IJoypad[Pet] then Ini.Joypad := Pet;

  // LCD
  Tekst := IniFile.ReadString('Devices',    'LPT',   ILPT[0]);
  for Pet := 0 to High(ILPT) do
    if Tekst = ILPT[Pet] then Ini.LPT := Pet;


  // SongPath
  if (Params.SongPath <> '') then
    SongPath := IncludeTrailingPathDelimiter(Params.SongPath)
  else
    SongPath := IncludeTrailingPathDelimiter(IniFile.ReadString('Path', 'Songs', SongPath));

  Filename := IniFile.FileName;
  IniFile.Free;
end;

procedure TIni.Save;
var
  IniFile:    TIniFile;
  Tekst:      string;
  I: Integer;
  S: String;
begin
  //if not (FileExists(GamePath + 'config.ini') and FileIsReadOnly(GamePath + 'config.ini')) then begin
  if not (FileExists(Filename) and FileIsReadOnly(Filename)) then begin

    IniFile := TIniFile.Create(Filename);

    // Players
    Tekst := IPlayers[Ini.Players];
    IniFile.WriteString('Game',     'Players',   Tekst);

    // Difficulty
    Tekst := IDifficulty[Ini.Difficulty];
    IniFile.WriteString('Game',     'Difficulty',   Tekst);

    // Language
    Tekst := ILanguage[Ini.Language];
    IniFile.WriteString('Game',     'Language',   Tekst);

    // Tabs
    Tekst := ITabs[Ini.Tabs];
    IniFile.WriteString('Game',     'Tabs',   Tekst);

    // Sorting
    Tekst := ISorting[Ini.Sorting];
    IniFile.WriteString('Game',     'Sorting',   Tekst);

    // Debug
    Tekst := IDebug[Ini.Debug];
    IniFile.WriteString('Game',     'Debug',   Tekst);

    // Screens
    Tekst := IScreens[Ini.Screens];
    IniFile.WriteString('Graphics', 'Screens', Tekst);

    // FullScreen
    Tekst := IFullScreen[Ini.FullScreen];
    IniFile.WriteString('Graphics', 'FullScreen', Tekst);

    // Resolution
    Tekst := IResolution[Ini.Resolution];
    IniFile.WriteString('Graphics', 'Resolution', Tekst);

    // Depth
    Tekst := IDepth[Ini.Depth];
    IniFile.WriteString('Graphics', 'Depth', Tekst);

    // Resolution
    Tekst := ITextureSize[Ini.TextureSize];
    IniFile.WriteString('Graphics', 'TextureSize', Tekst);

    // Sing Window
    Tekst := ISingWindow[Ini.SingWindow];
    IniFile.WriteString('Graphics', 'SingWindow', Tekst);

    // Oscilloscope
    Tekst := IOscilloscope[Ini.Oscilloscope];
    IniFile.WriteString('Graphics', 'Oscilloscope', Tekst);

    // Spectrum
    Tekst := ISpectrum[Ini.Spectrum];
    IniFile.WriteString('Graphics', 'Spectrum', Tekst);

    // Spectrograph
    Tekst := ISpectrograph[Ini.Spectrograph];
    IniFile.WriteString('Graphics', 'Spectrograph', Tekst);

    // Movie Size
    Tekst := IMovieSize[Ini.MovieSize];
    IniFile.WriteString('Graphics', 'MovieSize', Tekst);

    // MicBoost
    Tekst := IMicBoost[Ini.MicBoost];
    IniFile.WriteString('Sound',    'MicBoost',    Tekst);

    // ClickAssist
    Tekst := IClickAssist[Ini.ClickAssist];
    IniFile.WriteString('Sound',    'ClickAssist',    Tekst);

    // BeatClick
    Tekst := IBeatClick[Ini.BeatClick];
    IniFile.WriteString('Sound',    'BeatClick',    Tekst);

    // Threshold
    Tekst := IThreshold[Ini.Threshold];
    IniFile.WriteString('Sound',    'Threshold',    Tekst);

    // Song Preview
    Tekst := IPreviewVolume[Ini.PreviewVolume];
    IniFile.WriteString('Sound',    'PreviewVolume',    Tekst);

    Tekst := IPreviewFading[Ini.PreviewFading];
    IniFile.WriteString('Sound',    'PreviewFading',    Tekst);

    // SavePlayback
    Tekst := ISavePlayback[Ini.SavePlayback];
    IniFile.WriteString('Sound',    'SavePlayback',    Tekst);

    // Lyrics Font
    Tekst := ILyricsFont[Ini.LyricsFont];
    IniFile.WriteString('Lyrics',    'LyricsFont',    Tekst);

    // Lyrics Effect
    Tekst := ILyricsEffect[Ini.LyricsEffect];
    IniFile.WriteString('Lyrics',    'LyricsEffect',    Tekst);

    // Solmization
    Tekst := ISolmization[Ini.Solmization];
    IniFile.WriteString('Lyrics',    'Solmization',    Tekst);

    // Theme
    Tekst := ITheme[Ini.Theme];
    IniFile.WriteString('Themes',    'Theme',    Tekst);

    // Skin
    Tekst := ISkin[Ini.SkinNo];
    IniFile.WriteString('Themes',    'Skin',    Tekst);

    // Color
    Tekst := IColor[Ini.Color];
    IniFile.WriteString('Themes',    'Color',    Tekst);

    SaveInputDeviceCfg(IniFile);

    //Log.LogError(InttoStr(Length(CardList)) + ' Cards Saved');

    //Advanced Settings

    //LoadAnimation
    Tekst := ILoadAnimation[Ini.LoadAnimation];
    IniFile.WriteString('Advanced', 'LoadAnimation', Tekst);

    //EffectSing
    Tekst := IEffectSing[Ini.EffectSing];
    IniFile.WriteString('Advanced', 'EffectSing', Tekst);

    //ScreenFade
    Tekst := IScreenFade[Ini.ScreenFade];
    IniFile.WriteString('Advanced', 'ScreenFade', Tekst);

    //AskbeforeDel
    Tekst := IAskbeforeDel[Ini.AskbeforeDel];
    IniFile.WriteString('Advanced', 'AskbeforeDel', Tekst);

    //OnSongClick
    Tekst := IOnSongClick[Ini.OnSongClick];
    IniFile.WriteString('Advanced', 'OnSongClick', Tekst);

    //Line Bonus
    Tekst := ILineBonus[Ini.LineBonus];
    IniFile.WriteString('Advanced', 'LineBonus', Tekst);

    //Party Popup
    Tekst := IPartyPopup[Ini.PartyPopup];
    IniFile.WriteString('Advanced', 'PartyPopup', Tekst);

    // Joypad
    Tekst := IJoypad[Ini.Joypad];
    IniFile.WriteString('Controller',    'Joypad',    Tekst);

    IniFile.Free;
  end;
end;

procedure TIni.SaveNames;
var
  IniFile:    TIniFile;
  I:          integer;
begin
  //if not FileIsReadOnly(GamePath + 'config.ini') then begin
    //IniFile := TIniFile.Create(GamePath + 'config.ini');
  if not FileIsReadOnly(Filename) then begin
    IniFile := TIniFile.Create(Filename);

    //Name
      // Templates for Names Mod
    for I := 1 to 12 do
      IniFile.WriteString('Name', 'P' + IntToStr(I), Ini.Name[I-1]);
    for I := 1 to 3 do
      IniFile.WriteString('NameTeam', 'T' + IntToStr(I), Ini.NameTeam[I-1]);
    for I := 1 to 12 do
      IniFile.WriteString('NameTemplate', 'Name' + IntToStr(I), Ini.NameTemplate[I-1]);

    IniFile.Free;
  end;
end;

procedure TIni.SaveLevel;
var
  IniFile:    TIniFile;
  I:          integer;
begin
  //if not FileIsReadOnly(GamePath + 'config.ini') then begin
    //IniFile := TIniFile.Create(GamePath + 'config.ini');
  if not FileIsReadOnly(Filename) then begin
    IniFile := TIniFile.Create(Filename);

    // Difficulty
    IniFile.WriteString('Game', 'Difficulty', IDifficulty[Ini.Difficulty]);

    IniFile.Free;
  end;
end;

end.