I'm working on a game project, and I need to blindly be able to duplicate a class. Because Pascal cannot do this natively, what I'm doing is writing code for Assign so that I can assign from the original to the new. The usage of this would be for store inventory to a player's inventory in a RPG.

For instance, here's my Assign event for the base TItem class.

Code:
procedure TItem.Assign(From: TItem);
begin
  fCopied  := True;
  fName    := From.Name;
  fDesc    := From.Description;
  fIntName := From.InternalName;
  fValue   := From.Value;
  // No idea if the following will work!
  fAttr[0] := From.fAttr[0].ClassType.Create;
  fAttr[1] := From.fAttr[1].ClassType.Create;
  fAttr[0].Assign(From.fAttr[0]);
  fAttr[1].Assign(From.fAttr[1]);
end;
fAttr is a defined as: "array[0..1] of IAttribute". This sort of thing would be if you get a smith to harden your sword, you'd gain the attribute and it'd apply its bonus(es) to the item. Only trouble is, as you can see, I'm struggling to figure out if this sort of blind creation will work. Every Attribute, when I get them written, will have a Create call with no parameters and will be assigned to from the attribute derived from.

Ick, this is more complex than I had thought. I'll just post the source (it is all untested!).

What do you all think? Will this work, and if it won't then how can I fix it? I really need some kind of way to make a blind construction system like this.

Code:
// This source is private source code, please don't reuse it in your projects
// without my express written permission.
unit uWeapon;

interface

type
  TItem = class;

  // An attribute is a bonus to a given item.
  IAttribute = interface
    procedure ApplyTo(What: TItem);
    procedure Assign(From: IAttribute);
  end;
  IAttributePair  = Array[0..1] of IAttribute;

  // Placeholder class for a real inventory item class
  TItem = class
  private
    fCopied: Boolean;
    fName, fDesc, fIntName: String;
    fValue: Single;
    fAttr: IAttributePair;
    function  GetAttr(Index: Boolean): IAttribute;
    procedure SetAttr(Index: Boolean; Value: IAttribute);
  public
    property Name:         String read fName    write fName     default 'Unknown';
    property Description:  String read fDesc    write fDesc;
    property InternalName: String read fIntName write fIntName;
    property Value:        Single read fValue   write fValue    default 0.00;
    // Indexer...
    property Attributes[Index: Boolean]: IAttribute read GetAttr write SetAttr;
    // Constructor/destructor...
    constructor Create;
    destructor  Destroy;
    // Basic functions...
    procedure   Assign(From: TItem);
  end;

implementation

constructor TItem.Create;
begin
  fCopied  := False;
  fName    := 'Unknown';
  fDesc    := 'The mysterious unknown item!';
  fIntName := 'Item, Unknown';
  fValue   := 0.00;
  fAttr    := [nil, nil];
end;

destructor TItem.Destroy;
begin
  if Assigned(fAttr[0]) then
    FreeAndNil(fAttr[0]);
  if Assigned(fAttr[1]) then
    FreeAndNil(fAttr[1]);

  inherited Destroy;
end;

procedure TItem.Assign(From: TItem);
begin
  fCopied  := True;
  fName    := From.Name;
  fDesc    := From.Description;
  fIntName := From.InternalName;
  fValue   := From.Value;
  // No idea if the following will work!
  fAttr[0] := From.fAttr[0].ClassType.Create;
  fAttr[1] := From.fAttr[1].ClassType.Create;
  fAttr[0].Assign(From.fAttr[0]);
  fAttr[1].Assign(From.fAttr[1]);
end;

function TItem.GetAttr(Index: Boolean): IAttribute;
begin
  Result := fAttr[Ord(Index)];
end;

procedure TItem.SetAttr(Index: Boolean; Value: IAttribute);
begin
  if (Value := nil) and Assigned(fAttr[Ord(Index)]) then
    FreeAndNil(fAttr[Ord(Index)])
  else
    fAttr[Ord(Index)] := Value;
end;

end.