unit untScriptGenerator;

{$mode Delphi}{$H+}

interface

uses
  Classes, SysUtils, untCard;

type
  
  { TScriptGenerator }

  TScriptGenerator = class
  private
    class function CardOWnerToInt(AO: TCardOwner): Integer;
    class function CardPlayerToInt(AP: TCardPlayer): Integer;
    class function CardLocationToStr(AL: TCardLocation): String;
    class function CardLocationToInt(AL: TCardLocation): Integer;
    class function CardPositionToStr(AP: TCardPosition): String;
    class function CardXEPositionToStr(AP: TCardPosition): String;

    class function CardToVarName(ACard: TCard): String;
  public
    class function Generate(APuzzle: TPuzzleField): String;
  end;


implementation

uses
  untUtils;

class function TScriptGenerator.CardOWnerToInt(AO: TCardOwner): Integer;
begin
  Exit(IfThen<Integer>(AO = coSelf, 0, 1));
end;

class function TScriptGenerator.CardPlayerToInt(AP: TCardPlayer): Integer;
begin
  Exit(IfThen<Integer>(AP = cpSelf, 0, 1));
end;

class function TScriptGenerator.CardLocationToStr(AL: TCardLocation): String;
begin
  case AL of
  clDeck: Exit('LOCATION_DECK');
  clHand: Exit('LOCATION_HAND');
  clMZone: Exit('LOCATION_MZONE');
  clSZone: Exit('LOCATION_SZONE');
  clGrave: Exit('LOCATION_GRAVE');
  clRemoved: Exit('LOCATION_REMOVED');
  clExtra: Exit('LOCATION_EXTRA');
  end;
  Exit('');
end;

class function TScriptGenerator.CardLocationToInt(AL: TCardLocation): Integer;
begin
  case AL of
  clDeck: Exit(0);
  clHand: Exit(1);
  clMZone: Exit(2);
  clSZone: Exit(3);
  clGrave: Exit(4);
  clRemoved: Exit(5);
  clExtra: Exit(6);
  end;
  Exit(999);
end;

class function TScriptGenerator.CardPositionToStr(AP: TCardPosition): String;
begin
  case AP of
  cpUpAtk: Exit('POS_FACEUP_ATTACK');
  cpUpDef: Exit('POS_FACEUP_DEFENSE');
  cpDownDef: Exit('POS_FACEDOWN_DEFENSE');
  cpUp: Exit('POS_FACEUP');
  cpDown: Exit('POS_FACEDOWN');
  end;
  Exit('');
end;

class function TScriptGenerator.CardXEPositionToStr(AP: TCardPosition): String;
begin
  case AP of
  cpUpAtk: Exit('POS_FACEUP_ATTACK');
  cpUpDef, cpDownDef: Exit('POS_FACEUP_DEFENSE');
  end;
  Exit('');
end;

class function TScriptGenerator.CardToVarName(ACard: TCard): String;
begin
  // cardid, owner, player, location, seq
  Exit(Format('c%d_%d_%d_%d_%d', [
    ACard.CardId, 
    CardOWnerToInt(ACard.Owner), 
    CardPlayerToInt(ACard.Player), 
    CardLocationToInt(ACard.Location), 
    ACard.Seq
    ]));
end;

class function TScriptGenerator.Generate(APuzzle: TPuzzleField): String;
var
  list: TStringList;
  i, j, k: Integer;
  c: TCard;
begin
  list := TStringList.Create;

  // start
  list.Add(Format('Debug.SetAIName("%s")', [APuzzle.AIName]));
  list.Add('Debug.ReloadFieldBegin(DUEL_ATTACK_FIRST_TURN+DUEL_SIMPLE_AI)');
  list.Add(Format('Debug.SetPlayerInfo(0,%d,0,0)', [APuzzle.LPSelf]));
  list.Add(Format('Debug.SetPlayerInfo(1,%d,0,0)', [APuzzle.LPOpponent]));
  list.Add('');
  // message
  list.Add('--[[message');
  list.Add(APuzzle.Message);
  list.Add(']]');
  list.Add('');

  // body

  // body.0: add all card to list
  // hand
  for i := 0 to APuzzle.P0Hand.Count - 1 do begin
    c := APuzzle.P0Hand[i];
    list.Add(Format('Debug.AddCard(%d,0,0,LOCATION_HAND,0,%s)', [c.CardId, CardPositionToStr(c.Position)]));
  end;
  for i := 0 to APuzzle.P1Hand.Count - 1 do begin
    c := APuzzle.P1Hand[i];
    list.Add(Format('Debug.AddCard(%d,1,1,LOCATION_HAND,0,%s)', [c.CardId, CardPositionToStr(c.Position)]));
  end;
  // deck
  for i := 0 to APuzzle.P0Deck.Count - 1 do begin
    c := APuzzle.P0Deck[i];
    list.Add(Format('Debug.AddCard(%d,0,0,LOCATION_DECK,0,%s)', [c.CardId, CardPositionToStr(c.Position)]));
  end;
  for i := 0 to APuzzle.P1Deck.Count - 1 do begin
    c := APuzzle.P1Deck[i];
    list.Add(Format('Debug.AddCard(%d,1,1,LOCATION_DECK,0,%s)', [c.CardId, CardPositionToStr(c.Position)]));
  end;
  // extra deck
  for i := 0 to APuzzle.P0ExtraDeck.Count - 1 do begin
    c := APuzzle.P0ExtraDeck[i];
    list.Add(Format('Debug.AddCard(%d,0,0,LOCATION_EXTRA,0,%s)', [c.CardId, CardPositionToStr(c.Position)]));
  end;
  for i := 0 to APuzzle.P1ExtraDeck.Count - 1 do begin
    c := APuzzle.P1ExtraDeck[i];
    list.Add(Format('Debug.AddCard(%d,1,1,LOCATION_EXTRA,0,%s)', [c.CardId, CardPositionToStr(c.Position)]));
  end;
  // grave
  for i := 0 to APuzzle.P0Grave.Count - 1 do begin
    c := APuzzle.P0Grave[i];
    list.Add(Format('Debug.AddCard(%d,0,0,LOCATION_GRAVE,0,POS_FACEUP)', [c.CardId]));
  end;
  for i := 0 to APuzzle.P1Grave.Count - 1 do begin
    c := APuzzle.P1Grave[i];
    list.Add(Format('Debug.AddCard(%d,1,1,LOCATION_GRAVE,0,POS_FACEUP)', [c.CardId]));
  end;
  // removed
  for i := 0 to APuzzle.P0Removed.Count - 1 do begin
    c := APuzzle.P0Removed[i];
    list.Add(Format('Debug.AddCard(%d,0,0,LOCATION_REMOVED,0,%s)', [c.CardId, CardPositionToStr(c.Position)]));
  end;
  for i := 0 to APuzzle.P1Removed.Count - 1 do begin
    c := APuzzle.P1Removed[i];
    list.Add(Format('Debug.AddCard(%d,1,1,LOCATION_REMOVED,0,%s)', [c.CardId, CardPositionToStr(c.Position)]));
  end;

  list.Add('');

  // body.1: add all cards to field
  for i := 0 to 1 do begin
    for j := 0 to 4 do begin
      c := APuzzle.MCard[i, j];
      if c = nil then Continue;
      list.Add(Format('local %s = Debug.AddCard(%d,%d,%d,%s,%d,%s,%s)', [
        CardToVarName(c),                       // variable name
        c.CardId,                               // cardId
        CardOWnerToInt(c.Owner),                // owner
        CardPlayerToInt(c.Player),              // player
        CardLocationToStr(c.Location),          // location
        c.Seq,                                  // seq
        CardPositionToStr(c.Position),          // position
        IfThen<String>(c.Proc, 'true', 'false') // proc
      ]));
    end;
  end;
  for i := 0 to 1 do begin
    for j := 0 to 5 do begin
      c := APuzzle.SCard[i, j];
      if c = nil then Continue;
      list.Add(Format('local %s = Debug.AddCard(%d,%d,%d,%s,%d,%s)', [
        CardToVarName(c),                       // variable name
        c.CardId,                               // cardId
        CardOWnerToInt(c.Owner),                // owner
        CardPlayerToInt(c.Player),              // player
        CardLocationToStr(c.Location),          // location
        c.Seq,                                  // seq
        CardPositionToStr(c.Position)           // position
      ]));
    end;
  end;
  for i := 5 to 6 do begin
    c := APuzzle.ExtraMonster[i];
    if c = nil then Continue;
    list.Add(Format('local %s = Debug.AddCard(%d,%d,%d,%s,%d,%s,%s)', [
      CardToVarName(c),                       // variable name
      c.CardId,                               // cardId
      CardOWnerToInt(c.Owner),                // owner
      CardPlayerToInt(c.Player),              // player
      CardLocationToStr(c.Location),          // location
      c.Seq,                                  // seq
      CardPositionToStr(c.Position),          // position
      IfThen<String>(c.Proc, 'true', 'false') // proc
    ]));
  end;

  list.Add('');

  // body.2: add indicator
  for i := 0 to 1 do begin
    for j := 0 to 4 do begin
      c := APuzzle.MCard[i, j];
      if c = nil then Continue;
      if c.IndicatorCount > 0 then begin
        list.Add(Format('Debug.PreAddCounter(%s, 0x1F, %d)', [
          CardToVarName(c),                   // variable name
          c.IndicatorCount                    // count
        ]));
      end;
    end;
  end;

  for i := 0 to 1 do begin
    for j := 0 to 5 do begin
      c := APuzzle.SCard[i, j];
      if c = nil then Continue;
      if c.IndicatorCount > 0 then begin
        list.Add(Format('Debug.PreAddCounter(%s, 0x1F, %d)', [
          CardToVarName(c),                   // variable name
          c.IndicatorCount                    // count
        ]));
      end;
    end;
  end;

  for i := 5 to 6 do begin
    c := APuzzle.ExtraMonster[i];
    if c = nil then Continue;
    if c.IndicatorCount > 0 then begin
      list.Add(Format('Debug.PreAddCounter(%s, 0x1F, %d)', [
        CardToVarName(c),                   // variable name
        c.IndicatorCount                    // count
      ]));
    end;
  end;

  list.Add('');

  // body.3: add equip
  for i := 0 to 1 do begin
    for j := 0 to 4 do begin
      c := APuzzle.MCard[i, j];
      if c = nil then Continue;
      if c.EquipTo <> nil then begin
        list.Add(Format('Debug.PreEquip(%s, %s)', [
          CardToVarName(c),
          CardToVarName(c.EquipTo)
        ]));
      end;
    end;
  end;
  for i := 0 to 1 do begin
    for j := 0 to 5 do begin
      c := APuzzle.SCard[i, j];
      if c = nil then Continue;
      if c.EquipTo <> nil then begin
        list.Add(Format('Debug.PreEquip(%s, %s)', [
          CardToVarName(c),
          CardToVarName(c.EquipTo)
        ]));
      end;
    end;
  end;
  for i := 5 to 6 do begin
    c := APuzzle.ExtraMonster[i];
    if c = nil then Continue;
    if c.EquipTo <> nil then begin
      list.Add(Format('Debug.PreEquip(%s, %s)', [
        CardToVarName(c),
        CardToVarName(c.EquipTo)
      ]));
    end;
  end;

  list.Add('');

  // body.4: add continous effect
  for i := 0 to 1 do begin
    for j := 0 to 4 do begin
      c := APuzzle.MCard[i, j];
      if c = nil then Continue;
      if c.ContinousEffectTo.Count > 0 then begin
        for k := 0 to c.ContinousEffectTo.Count - 1 do begin
          list.Add(Format('Debug.PreSetTarget(%s, %s)', [
            CardToVarName(c),
            CardToVarName(c.ContinousEffectTo[k])
          ]));
        end;
      end;
    end;
  end;

  for i := 0 to 1 do begin
    for j := 0 to 5 do begin
      c := APuzzle.SCard[i, j];
      if c = nil then Continue;
      if c.ContinousEffectTo.Count > 0 then begin
        for k := 0 to c.ContinousEffectTo.Count - 1 do begin
          list.Add(Format('Debug.PreSetTarget(%s, %s)', [
            CardToVarName(c),
            CardToVarName(c.ContinousEffectTo[k])
          ]));
        end;
      end;
    end;
  end;

  for i := 5 to 6 do begin
    c := APuzzle.ExtraMonster[i];
    if c = nil then Continue;
    if c.ContinousEffectTo.Count > 0 then begin
      for k := 0 to c.ContinousEffectTo.Count - 1 do begin
        list.Add(Format('Debug.PreSetTarget(%s, %s)', [
          CardToVarName(c),
          CardToVarName(c.ContinousEffectTo[k])
        ]));
      end;
    end;
  end;

  list.Add('');

  // body.5 xyz elements
  for i := 0 to 1 do begin
    for j := 0 to 4 do begin
      c := APuzzle.MCard[i, j];
      if c = nil then Continue;
      if not c.IsXyzMonster then Continue;
      if c.XyzElements.Count > 0 then begin
        for k := 0 to c.XyzElements.Count - 1 do begin
          list.Add(Format('Debug.AddCard(%d,%d,%d,LOCATION_MZONE,%d,%s)', [
            c.XyzElements[k],
            CardOWnerToInt(c.Owner),
            CardPlayerToInt(c.Player),
            c.Seq,
            CardXEPositionToStr(c.Position)
          ]));
        end;
      end;
    end;
  end;

  list.Add('');

  // body.6 work as
  for i := 0 to 1 do begin
    for j := 0 to 4 do begin
      c := APuzzle.MCard[i, j];
      if c = nil then Continue;
      if c.WorkAs <> waOrigin then begin
        list.Add(Format('Card.AssumeProperty(%s,ASSUME_TYPE,%s)', [
          CardToVarName(c),
          WorkAsToCodeName(c.WorkAs)
        ]));
      end;
    end;
  end;
  for i := 0 to 1 do begin
    for j := 0 to 5 do begin
      c := APuzzle.SCard[i, j];
      if c = nil then Continue;
      if c.WorkAs <> waOrigin then begin
        list.Add(Format('Card.AssumeProperty(%s,ASSUME_TYPE,%s)', [
          CardToVarName(c),
          WorkAsToCodeName(c.WorkAs)
        ]));
      end;
    end;
  end;
  for i := 5 to 6 do begin
    c := APuzzle.ExtraMonster[i];
    if c = nil then Continue;
    if c.WorkAs <> waOrigin then begin
      list.Add(Format('Card.AssumeProperty(%s,ASSUME_TYPE,%s)', [
          CardToVarName(c),
          WorkAsToCodeName(c.WorkAs)
        ]));
    end;
  end;

  list.Add('');

  // end
  list.Add('Debug.ReloadFieldEnd()');
  list.Add('Debug.ShowHint("Win this turn")');
  list.Add('aux.BeginPuzzle()');
  list.Add('');

  // solution
  list.Add('--[[');
  list.Add('Solution:');
  list.Add(APuzzle.Solution);
  list.Add(']]');

  Result := list.Text;

  list.Free
end;

end.

