PDA

View Full Version : Function and Procedure 'variables'.



Wizzup?
03-10-2008, 03:39 PM
Well, this is a cool thing you can do in SCAR, I don't know how usefull it is, but it is still pretty cool. :p

Say, you got this program:

program New;

procedure writemessage(s: String);

begin
writeln(s);
end;

begin
writemessage('hello');
end.

This will write hello in your debug.

You can make 'shortcuts', as I like to call them, to this procedure.
A shortcut can be made by adding an @+ProcedureName.
Write:=@WriteMessage;

You might know this way of adressing functions, I was first introduced to them when I worked with forms and TTimers.

Timer.OnTimer := @SomeProcedure;
// Or
Button.OnClick := @SomeProcedure;

program New;

procedure writemessage(s: String);

begin
writeln(s);
end;

Var
Write: Procedure (avar: string);

begin
Write := @WriteMessage;
Write('hello');
end.

Please not that the shortcut's procedure input and output (only for functions) has to be the same.

A simple example with a function:

program New;

procedure writemessage(s: String);

begin
writeln(s);
end;

function returnnumber:integer;

begin
result := 5;
end;

Var
Write: Procedure (avar: string);
Number: Function: Integer;

begin
Write := @WriteMessage;
Number := @ReturnNumber;
Write(IntToStr(Number()));
end.

Please note the Number(), if you don't add this SCAR will interpret it as a type mismatch.

You can also remove the link from the shortcut by simply setting it to nil.

Write := nil;

You can make it more complicated.
I wrote this when I was experimenting on using multiple locations (Lumbridge, Varrock) in one script, without using cases in walking (Like VYC does).

First, I made a record of a Location.

Type
TLocation = Record
Name: String;
ToMine, ToBank, BankItems, Start, Stop: Procedure;
MyMine: Function: Boolean;
End;
TLocationArray = Array Of TLocation;
Var
Locations: TLocationArray;
CurrentLocation: TLocation;


Load the Locations array like this:


Procedure LoadLocations;

Begin
SetLength(Locations, 1);
Locations[0].Name := 'VEM';
Locations[0].ToMine := @VEM_ToMine;
Locations[0].ToBank := @VEM_ToBank;
Locations[0].BankItems := @VEM_BankStuff;
Locations[0].MyMine := @VEM_MyMine;
End;


This way your mainloop could look like this:

Repeat
ResetLocation(CurrentLocation);
CurrentLocation := Fetch_Location(Players[CurrentPlayer].Strings[3]);
{This string (Strings[3]) holds the location name.
Fetch_Location returns a TLocation. }


CurrentLocation.Start();
If Players[CurrentPlayer].Loc = 'Bank' Then
Begin
CurrentLocation.ToMine();
End;

If Players[CurrentPlayer].Loc = 'Mine' Then
Begin
Repeat
Wait(100);
If Not CurrentLocation.MyMine() Then
Wait(50);
If FlagPresent Then
Wait(2000 + Random(500));
FindNormalRandoms;
If Not LoggedIn Then Break;
If Not FindPick then Break;
Until (InvFull Or ((GetSystemTime - MyTimer) > 60000 * MinutesPerLoad));

CurrentLocation.ToBank();
CurrentLocation.BankItems();
End;
ProgressReport;
CurrentLocation.Stop();
//Something with player logging in and out.
Until False;

Fetch_Location could look like this:

Function Fetch_Location(Name: string): TLocation;

Var
I: Integer;
Begin
Name := LowerCase(Name);
For I := Low(Locations) To High(Locations) Do
If Name = LowerCase(Locations[I].Name) Then
Begin
Result := Locations[I];
Exit;
End;
End;


You can also make Array of Function/Procedure.

program New;

type TFuncArray = Array Of Function: Integer;

Var
a: TFuncArray;

Function Return1: Integer;

Begin
result := 8;
End;

Function Return2: Integer;

Begin
result := 4;
End;

var
count: integer;
begin
setlength(a, 2);
a[0] := @return1;
a[1] := @return2;
for count := 0 to 1 do
writeln(inttostr(a[count]()));
end.

I hope this helped.

Raymond, SKy, nielsie and everyone else:
Please correct me on name-mistakes, general mistakes, extra features, or anything else that you think I should change or add to this tutorial.

~Wizzup?

mastaraymond
03-10-2008, 07:08 PM
I hope this helped.


This tutorial helped me very much to get really cool mainloops like you.. Thanks!

Yakman
03-10-2008, 07:11 PM
wow this is great, its a lot like function pointers in C

SKy Scripter
03-13-2008, 12:36 AM
Dis how i did my randoms :)

I wish i didn't have problems doing this

Procs := [@FindTalk, @FindIven, FindTeled];

or something like that :)

bullzeye95
03-13-2008, 12:55 AM
You can also remove the link from the shortcut by simply setting it to nil.

Write := nil;


Didn't know that, thanks :)
That's the first thing I've learned in a long time =/

stampede10343
03-13-2008, 01:02 AM
i've never seen that before, at first im like a procedures and functions tut in advanced, better check it out. But its pretty advanced but its good to know this thanks!

mastaraymond
03-13-2008, 02:47 PM
Didn't know that, thanks :)
That's the first thing I've learned in a long time =/
You would've know it, I've used it before =].. Guess in what "game".. ;)

Negaal
03-16-2008, 11:10 AM
This tutorial helped me very much to get really cool mainloops like you.. Thanks!

Though you rarely release a script.

Anyways, didn't knew I can manipulate with functions. Now I do, thanks for this.

mastaraymond
03-16-2008, 12:57 PM
Though you rarely release a script.

Anyways, didn't knew I can manipulate with functions. Now I do, thanks for this.
It was sarcastic ;)

1337.
03-25-2008, 12:59 AM
Pretty interesting, had always suspected after seeing it being used in forms as well... Surprised I never bothered to find out earlier :P

Thanks for this, but are there any other benefits apart from saving coding time and keeping code neater (performance benefits etc..)? Just because I wonder if this would effect the scripting standards...?

Wizzup?
03-25-2008, 03:32 PM
Pretty interesting, had always suspected after seeing it being used in forms as well... Surprised I never bothered to find out earlier :P

Thanks for this, but are there any other benefits apart from saving coding time and keeping code neater (performance benefits etc..)? Just because I wonder if this would effect the scripting standards...?

I have combined some Mining scripts of mine.
I'll post a few samples:

Type
TLocalVar = Record
Value: Variant;
IsSet: Boolean;
Name, vType: String;
End;
TLocals = Array Of TLocalVar;

TMineInfo = Record
HasNewRocks: Boolean;
GasCheck, IsNewRock: Function (P: TPoint): Boolean;
Ores: TStringArray;
MMRockName, RunDir: String;
MineDist: Integer;
End;

TFunctionBArray = Array Of Function: Boolean;

tExtraFunc = Record
Func: TFunctionBArray;
PointInScript: Integer;
End;

TExtraFuncArray = Array Of tExtraFunc;

TLocation = Record
Name: String;
ToMine, ToBank, SetOreColor, Start, Stop: Procedure;
OpenBank: Function: Boolean;
AutoColorOptions: Array Of String;
MineInfo: TMineInfo;
LocalVars: TLocals;
Loads, TimeRan, WorkedTimer: Integer;
Funcs: TExtraFuncArray;
End;
TLocationArray = Array Of TLocation;

myReport = Record
Bmp, Value: Integer;
Name, wType: String;
End;
TReportArray = Array [0..19] Of myReport;


Const
LOC_BANK = 0;
LOC_ATMINE = 1;
LOC_MINING = 2;
LOC_DONEMINING = 3;
LOC_AFTERFIGHT = 4;

Var
Locations: TLocationArray;
CurrentLocation: TLocation;
ReportArray: TReportArray;


Function ExtraFuncs(Current: Integer): Array Of Boolean;

Var
I , C: Integer;
Begin
For I := 0 To High(CurrentLocation.Funcs) Do
If Current = CurrentLocation.Funcs[I].PointInScript Then
Begin
SetLength(Result, Length(CurrentLocation.Funcs[I].Func));
For C := 0 To High(CurrentLocation.Funcs[I].Func) Do
CurrentLocation.Funcs[I].Func[C]();
Exit;
End;
End;

Location loading.

Procedure LoadLocations;

Begin
SetLength(Locations, 2);
With Locations[0] Do
Begin
Name := 'VEM';
ToMine := @VEM_ToMine;
ToBank := @VEM_ToBank;
Start := @VEM_Start;
Stop := @VEM_Stop;
OpenBank := @VEM_EasyBank;
SetOreColor := @VEM_SetOreColor;
AutoColorOptions := ['anvil'];
Loads := VEMLoads;

SetLength(Funcs, 0);
SetLength(LocalVars, 0);

With MineInfo Do
Begin
HasNewRocks := True;
IsNewRock := @VEM_IsNewRock;
GasCheck := @w_GasCheck;
Ores := ['Iron', 'Tin', 'Copper'];
MMRockName := 'brown rock';
RunDir := 'S';
MineDist := 34;
End;
End;

With Locations[1] Do
Begin
Name := 'LSM';
ToMine := @LSM_ToMine;
ToBank := @LSM_ToBank;
Start := @LSM_Start;
Stop := @LSM_Stop;
OpenBank := @LSM_OpenBank;
SetOreColor := @LSM_SetOreColor;
AutoColorOptions := ['bank'];
Loads := LSMLoads;
SetLength(Funcs, 2);

With Funcs[0] Do
Begin
SetLength(Func, 1);
Func[0] := @LSM_SetCallibrateTimer;
PointInScript := LOC_ATMINE;
End;

With Funcs[1] Do
Begin
SetLength(Func, 1);
Func[0] := @LSM_Callibrate;
PointInScript := LOC_MINING;
End;

SetLength(LocalVars, 2);
With LocalVars[0] Do
Begin
Name := 'Draynor Bank DTM';
IsSet := False;
Value := 0;
vType := 'DTM';
End;

With LocalVars[1] Do
Begin
Name := 'Callibrate Timer';
IsSet := False;
Value := 0;
vType := 'Timer';
End;

With MineInfo Do
Begin
HasNewRocks := True;
IsNewRock := @LSM_IsNewRock;
GasCheck := @w_GasCheck;
Ores := ['Coal', 'Mithril', 'Adamant'];
MMRockName := 'brown rock';
RunDir := 'E';
MineDist := 50;
End;
End;

And the mainloop:

begin
SetupScript;

Repeat
FreeLocation(CurrentLocation);
Fetch_Location(CurrentLocation);
CurrentLocation.Start();

If Players[CurrentPlayer].Loc = 'Bank' Then
Begin
Location_Debug('Going to the Mine');

ExtraFuncs(LOC_BANK);

Try
CurrentLocation.ToMine();
Except End;
End;

If Players[CurrentPlayer].Loc = 'Mine' Then
Begin

ExtraFuncs(LOC_ATMINE);

Players[CurrentPlayer].Level[15] := GetSkillInfo('mining', False);
SetRun(True);

Location_Debug('Players.Loc = Mine');
Location_Debug('Starting Mine Loop.');

MyTimer := GetSystemTime;

Repeat
Wait(200);
If Not MyMine Then
if TooFar then
If MiddleOfMine(Dx, Dy) Then
Begin
Location_Debug('Walking back to the mine');
Mouse(Dx, Dy, 2, 2, True);
FFlag(0);
End;
If FlagPresent Then
Wait(2000+Random(500));

ExtraFuncs(LOC_MINING);

FindNormalRandomsTimeEx;

If Not LoggedIn Then
Begin
Location_Debug('Not Logged-In, breaking.');
Break;
End;
If Not FindPick Then
Begin
Location_Debug('No FindPick, breaking.');
Break;
End;
Until (InvFull Or ((GetSystemTime - MyTimer) > 60000 * MinutesPerLoad));

ExtraFuncs(LOC_DONEMINING);

Location_Debug('Walking to the bank.');

Try
CurrentLocation.ToBank();
Except End;

Location_Debug('Players.Loc := Bank');

Bank;
End;

If LoggedIn And (Players[CurrentPlayer].Banked Mod CurrentLocation.Loads = 0) Then
Begin
WriteLn('Switching Players. Time to leave, ' + Players[CurrentPlayer].Name + '.');
LogOut;
NextPlayer(True);
InitPlayer;
End;

If Not LoggedIn Then
Begin
NextPlayer(False);
NoPick := False;
InitPlayer;
If NoPick Then LogOut;
End;

CurrentLocation.Stop();

ProgressReport;
Until False;
end.

Bobarkinator
03-27-2008, 03:07 AM
Very nice. I may try them out.