unit untScriptGenerator;

interface

uses
  Classes, SysUtils, untCard, StrUtils;

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 CardExtraSeq(AO: TCardOwner; ASeq: Integer): Integer;
    class function CardLocationToInt(AL: TCardLocation): Integer;
    class function CardPositionToStr(AP: TCardPosition): String;
    class function CardXEPositionToStr(AP: TCardPosition): String;
    class function CardToVarName(ACard: ICard): String;
    class function CardAttributeToStr(AAtrr: Int64): string;
    class function CardRaceToStr(ARace: Int64): string;
  public
    class function Generate(APuzzle: TPuzzleField): String;
    class function GenerateOverride(ACard: ICard): string;
  end;

implementation

uses
  untUtils, untArrayHelper, untAttrRace;

{ TScriptGenerator }

class function TScriptGenerator.CardAttributeToStr(AAtrr: Int64): string;
begin
  Exit(TYGOValueList.AttrIdToItem(AAtrr).Second);
end;

class function TScriptGenerator.CardExtraSeq(AO: TCardOwner; ASeq: Integer): Integer;
begin
  case AO of
  coSelf: Exit(ASeq);
  coOpponent: if (ASeq = 5) then Exit(6) else Exit(5);
  end;
  Exit(0);
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.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.CardOWnerToInt(AO: TCardOwner): Integer;
begin
  Exit(EXT.IfThen(AO = coSelf, 0, 1));
end;

class function TScriptGenerator.CardPlayerToInt(AP: TCardPlayer): Integer;
begin
  Exit(EXT.IfThen<Integer>(AP = cpSelf, 0, 1));
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.CardRaceToStr(ARace: Int64): string;
begin
  Exit(TYGOValueList.RaceIdToItem(ARace).Second);
end;

class function TScriptGenerator.CardToVarName(ACard: ICard): String;
begin
  // cardid, owner, player, location, seq
  Exit(Format('c%d_%d_%d_%d_%d', [
    ACard.GetCardId,
    CardOWnerToInt(ACard.GetOwner),
    CardPlayerToInt(ACard.GetPlayer),
    CardLocationToInt(ACard.GetLocation),
    ACard.GetSeq
    ]));
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.Generate(APuzzle: TPuzzleField): String;
var
  list: TStringList;
  i, j, k: Integer;
  c: ICard;
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.GetCardId, CardPositionToStr(c.GetPosition)]));
  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.GetCardId, CardPositionToStr(c.GetPosition)]));
  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.GetCardId, CardPositionToStr(c.GetPosition)]));
  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.GetCardId, CardPositionToStr(c.GetPosition)]));
  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.GetCardId, CardPositionToStr(c.GetPosition)]));
  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.GetCardId, CardPositionToStr(c.GetPosition)]));
  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.GetCardId]));
  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.GetCardId]));
  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.GetCardId, CardPositionToStr(c.GetPosition)]));
  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.GetCardId, CardPositionToStr(c.GetPosition)]));
  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.GetCardId,                               // cardId
        CardOWnerToInt(c.GetOwner),                // owner
        CardPlayerToInt(c.GetPlayer),              // player
        CardLocationToStr(c.GetLocation),          // location
        c.GetSeq,                                  // seq
        CardPositionToStr(c.GetPosition),          // position
        EXT.IfThen(c.GetProc, '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.GetCardId,                               // cardId
        CardOWnerToInt(c.GetOwner),                // owner
        CardPlayerToInt(c.GetPlayer),              // player
        CardLocationToStr(c.GetLocation),          // location
        c.GetSeq,                                  // seq
        CardPositionToStr(c.GetPosition)           // 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.GetCardId,                               // cardId
      CardOWnerToInt(c.GetOwner),                // owner
      CardPlayerToInt(c.GetPlayer),              // player
      CardLocationToStr(c.GetLocation),          // location
      CardExtraSeq(c.GetOwner, c.GetSeq),           // seq
      CardPositionToStr(c.GetPosition),          // position
      EXT.IfThen(c.GetProc, '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.GetIndicatorCount > 0 then begin
        list.Add(Format('Debug.PreAddCounter(%s, 0x1F, %d)', [
          CardToVarName(c),                   // variable name
          c.GetIndicatorCount                    // 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.GetIndicatorCount > 0 then begin
        list.Add(Format('Debug.PreAddCounter(%s, 0x1F, %d)', [
          CardToVarName(c),                   // variable name
          c.GetIndicatorCount                    // count
        ]));
      end;
    end;
  end;

  for i := 5 to 6 do begin
    c := APuzzle.ExtraMonster[i];
    if c = nil then Continue;
    if c.GetIndicatorCount > 0 then begin
      list.Add(Format('Debug.PreAddCounter(%s, 0x1F, %d)', [
        CardToVarName(c),                   // variable name
        c.GetIndicatorCount                    // 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.GetEquipTo <> nil then begin
        list.Add(Format('Debug.PreEquip(%s, %s)', [
          CardToVarName(c),
          CardToVarName(c.GetEquipTo)
        ]));
      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.GetEquipTo <> nil then begin
        list.Add(Format('Debug.PreEquip(%s, %s)', [
          CardToVarName(c),
          CardToVarName(c.GetEquipTo)
        ]));
      end;
    end;
  end;
  for i := 5 to 6 do begin
    c := APuzzle.ExtraMonster[i];
    if c = nil then Continue;
    if c.GetEquipTo <> nil then begin
      list.Add(Format('Debug.PreEquip(%s, %s)', [
        CardToVarName(c),
        CardToVarName(c.GetEquipTo)
      ]));
    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.GetContinousEffectTo.Count > 0 then begin
        for k := 0 to c.GetContinousEffectTo.Count - 1 do begin
          list.Add(Format('Debug.PreSetTarget(%s, %s)', [
            CardToVarName(c),
            CardToVarName(c.GetContinousEffectTo[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.GetContinousEffectTo.Count > 0 then begin
        for k := 0 to c.GetContinousEffectTo.Count - 1 do begin
          list.Add(Format('Debug.PreSetTarget(%s, %s)', [
            CardToVarName(c),
            CardToVarName(c.GetContinousEffectTo[k])
          ]));
        end;
      end;
    end;
  end;

  for i := 5 to 6 do begin
    c := APuzzle.ExtraMonster[i];
    if c = nil then Continue;
    if c.GetContinousEffectTo.Count > 0 then begin
      for k := 0 to c.GetContinousEffectTo.Count - 1 do begin
        list.Add(Format('Debug.PreSetTarget(%s, %s)', [
          CardToVarName(c),
          CardToVarName(c.GetContinousEffectTo[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.GetIsXyzMonster then Continue;
      if c.GetXyzElements.Count > 0 then begin
        for k := 0 to c.GetXyzElements.Count - 1 do begin
          list.Add(Format('Debug.AddCard(%d,%d,%d,LOCATION_MZONE,%d,%s)', [
            c.GetXyzElements[k],
            CardOWnerToInt(c.GetOwner),
            CardPlayerToInt(c.GetPlayer),
            c.GetSeq,
            CardXEPositionToStr(c.GetPosition)
          ]));
        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.GetWorkAs <> waOrigin then begin
        list.Add(Format('Card.AssumeProperty(%s,ASSUME_TYPE,%s)', [
          CardToVarName(c),
          WorkAsToCodeName(c.GetWorkAs)
        ]));
      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.GetWorkAs <> waOrigin then begin
        list.Add(Format('Card.AssumeProperty(%s,ASSUME_TYPE,%s)', [
          CardToVarName(c),
          WorkAsToCodeName(c.GetWorkAs)
        ]));
      end;
    end;
  end;
  for i := 5 to 6 do begin
    c := APuzzle.ExtraMonster[i];
    if c = nil then Continue;
    if c.GetWorkAs <> waOrigin then begin
      list.Add(Format('Card.AssumeProperty(%s,ASSUME_TYPE,%s)', [
          CardToVarName(c),
          WorkAsToCodeName(c.GetWorkAs)
        ]));
    end;
  end;

  list.Add('');

  // body.7 property override
  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(GenerateOverride(c));
    end;
  end;

  for i := 5 to 6 do begin
    c := APuzzle.ExtraMonster[i];
    if c = nil then Continue;
    list.Add(GenerateOverride(c));
  end;

  // 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;

class function TScriptGenerator.GenerateOverride(ACard: ICard): string;
var
  list: TStringList;
begin
  list := TStringList.Create;

  if ACard.GetOverride.GetUseLevel then begin
    list.Add(Format('Card.AssumeProperty(%s,ASSUME_LEVEL,%d)', [
      CardToVarName(ACard),
      ACard.GetOverride.GetLevel
    ]));
  end;
  if ACard.GetOverride.GetUseRank then begin
    list.Add(Format('Card.AssumeProperty(%s,ASSUME_RANK,%d)', [
      CardToVarName(ACard),
      ACard.GetOverride.GetRank
    ]));
  end;
  if ACard.GetOverride.GetUseAttr then begin
    list.Add(Format('Card.AssumeProperty(%s,ASSUME_ATTRIBUTE,%s)', [
      CardToVarName(ACard),
      CardAttributeToStr(ACard.GetOverride.GetAttr)
    ]));
  end;
  if ACard.GetOverride.GetUseRace then begin
    list.Add(Format('Card.AssumeProperty(%s,ASSUME_RACE,%s)', [
      CardToVarName(ACard),
      CardRaceToStr(ACard.GetOverride.GetRace)
    ]));
  end;
  if ACard.GetOverride.GetUseAtk then begin
    list.Add(Format('Card.AssumeProperty(%s,ASSUME_ATTACK,%d)', [
      CardToVarName(ACard),
      ACard.GetOverride.GetAtk
    ]));
  end;
  if ACard.GetOverride.GetUseDef then begin
    list.Add(Format('Card.AssumeProperty(%s,ASSUME_DEFENSE,%d)', [
      CardToVarName(ACard),
      ACard.GetOverride.GetDef
    ]));
  end;

  Result := list.Text;
  list.Free;
end;

end.
