SRL Archive - MSI Suggestions

Procedural Pointers


Coh3n

2010-07-27 20:20:43

[INDENT]This was suggested to me by Nava2, and after half an hour or so of explaining/me looking like a dumbass, I finally (kind of) understood what he was talking about. Not exactly sure what took me so long because it's pretty straight forward.

Basically, he suggested using Procedure Pointers in our TScript records. This will make scripts more customizable and gives an object oriented programming (OOP) kind of feel to it as functions can be "overridden" using pointers. If you have no idea what I'm talking about, don't worry, I'll try to explain.


program new;
{$i srl/srl.scar}

type
TScript = record;
Name: string;
WalkToLoc: function(startLoc, endLoc: Integer): Boolean;
end;

function WalkToLocDefault(startLoc, endLoc): Boolean;
begin
end;

function WalkToLocWithGate(startLoc, endLoc): Boolean;
begin
end;

function LoadScript(Which: Integer): TScript;
begin
case Which of
EXAMPLE_1:
with Result do
begin
Name := 'Example_1';
WalkToLoc := @WalkToLocDefault(LOC_BANK, LOC_TREES);
end;

EXAMPLE_2:
with Result do
begin
Name := 'Example_2';
WalkToLoc := @WalkToLocWithGate(LOC_BANK, LOC_TREES); // If there's a gate in the path, we won't use the default walking function
end;
end;
end;

function MSI_WalkToLoc: Boolean; // This would be the function in Mainloop.scar
var
Script: TScript;
begin
Script := MSI_Scripts[MSI_Players[CurrentPlayer].Scripts[CurrentScript]];

if (Script.WalkToLoc <> nil) then // If .WalkToLoc has been set
Result := Script.WalkToLoc
else
Result := WalkToLocDefault(Script.StartLoc, Script.EndLoc);
end;

begin
end.

Similar strategies can be done with Object finding/location finding (when the relocator is developed), etc.

I wrote this quick, so if you don't understand, just ask. But anyway, I just want to discuss this for now, see what people think. :)[/INDENT]

Nava2

2010-07-27 20:28:01

:D for good examples of this, check out the srl_Procs in SRL, or Wizzup/Fawki's multi miner.

NCDS

2010-07-27 20:36:57

After a bit of re-reading up on them, I 100% agree ;)

Wanted

2010-07-27 20:43:07

From: Nava2
:D for good examples of this, check out the srl_Procs in SRL, or Wizzup/Fawki's multi miner.


SRL\Core\Antirandoms\Antirandoms.scar is also a good place for examples.

NCDS

2010-07-27 20:48:32

I think (hope) that everyone will be able to understand just from what Coh3n posted.

marpis

2010-07-28 04:58:29

I don't think this would be anyhow better than the current system. Would just produce hellalotta more functions to MSI and make adding scripts slightly more difficult (instead of just inputing the path you need to make a function for it in Walking.scar)

EDIT: Oh now that I read the last part of script I'm a bit confused :rolleyes:

Coh3n

2010-07-28 11:39:41

From: marpis
I don't think this would be anyhow better than the current system. Would just produce hellalotta more functions to MSI and make adding scripts slightly more difficult (instead of just inputing the path you need to make a function for it in Walking.scar)

EDIT: Oh now that I read the last part of script I'm a bit confused :rolleyes:

Okay. Well, it wouldn't make it more complicated (well maybe slightly, but not a whole lot). We would still be adding the paths to the TScript record and we wouldn't have to add another function unless there needs to be a specific function for that script (i.e. a walking path where you need to open a door half way through), everything else would use a default function similar to what we use now.

If by last part you mean the part that would be added in Mainloop.scar, that simply means that if the WalkToLoc attribute isn't set when loading the TScript record, it will use the default walking function. So, unless there is something special about that script's path, you don't have to use the WalkToLoc attribute when making the record.

I hope that made sense. :p

Oh, and if this were to be added today, we wouldn't have any extra functions (there would just be some renaming of some).

marpis

2010-07-28 13:55:45

From: Coh3n
Okay. Well, it wouldn't make it more complicated (well maybe slightly, but not a whole lot). We would still be adding the paths to the TScript record and we wouldn't have to add another function unless there needs to be a specific function for that script (i.e. a walking path where you need to open a door half way through), everything else would use a default function similar to what we use now.

If by last part you mean the part that would be added in Mainloop.scar, that simply means that if the WalkToLoc attribute isn't set when loading the TScript record, it will use the default walking function. So, unless there is something special about that script's path, you don't have to use the WalkToLoc attribute when making the record.

I hope that made sense. :p

Oh, and if this were to be added today, we wouldn't have any extra functions (there would just be some renaming of some).


Now I got it! :)
Yea that sounds good. But I have another idea:
Let's change WalkTo a bit.

function MSI_WalkTo(startLoc, endLoc, SpecialWalkIndex: integer): boolean;
and add a property SpecialWalkIndex to TScript.

MSI_WalkTo(startLoc, endLoc, SpecialWalkIndex);
and also add the special gate opening or something property to TScript, like "SpecialWalk: function: boolean" and set the gate opening pointer in the script record.

SpecialWalkToLoc := @CraftingGuildDoorIn();
SpecialWalkToBank := @CraftingGuildDoorOut();

and in MSI_ReflectionWalk, let's edit the loop to check if current walk index is the SpecialWalkIndex. If it is, call the function SpecialWalkToLoc() or SpecialWalkToBank().

Could also be implemented as arrays, to make it possible to have multiple special indexes.

How do you like this implementation of the same idea?

Naum

2010-07-28 14:04:31

I thought we did this already to some extent?
The problem with procedural pointers are that there aren't that many tutorials on them, therefore we must take into account what people know, or else teach them.
Looks k.

EDIT: By the way: Happy birthday Nava, hope you have a good one bro

Blumblebee

2010-07-28 14:15:58

there's actually a few pointer tutorials out there, and it's not like its hard to understand @procedure;

Good to see that we're doing this, I love pointers :) (for no specific reason haha)

Coh3n

2010-07-28 14:29:48

marpis, not that I don't like your idea, but I don't want to have to add parameters. I would rather keep them as separate functions, if possible. I don't want things to get cluttered or anything. I would also rather just keep the WalkToLoc/Bank attributes to the record, rather than adding an extra two.

I do see what you're saying about the index thing though because somehow we would have to let the script know which walk index to look for the obstacle. What I had in mind was just look for it at every point, but that wouldn't work seeing as there could be multiple doors for example along the path (or even on the same point for that matter).

But anyway, I like the idea of "overriding" the default walking procedure more than adding a parameter and slightly complicating the current one. I feel it would be more organized and understandable that way.

There may have to be an ObstacleIndex added to the TScript record, but I don't see that being a huge issue. After all, if we want the script to run purely on the script record, it's bound to get quite large. :rolleyes:

Nava2

2010-07-28 16:44:55

I think that having an array for walking obstacles would be cool:

type TScript = record
WalkObstacles: array of function(): Boolean;

Then, when you call WalkToX, for each step, check if there is an obstacle function. If there is, use it, otherwise its nil and you can progress.


function WalkTo(x, y: Integer): Boolean;
begin
for i := x to y do
begin
if (Script.WalkObstacles[i]() <> nil) then
Script.WalkObstacles[i]();
//...
end;
end;

Coh3n

2010-07-28 16:46:43

From: Nava2
I think that having an array for walking obstacles would be cool:

type TScript = record
WalkObstacles: array of function(): Boolean;

Then, when you call WalkToX, for each step, check if there is an obstacle function. If there is, use it, otherwise its nil and you can progress.

So WalkObstacles would be the same length as the path, where each index is a function looking for a certain obstacle?

Nava2

2010-07-28 16:51:51

From: Coh3n
So WalkObstacles would be the same length as the path, where each index is a function looking for a certain obstacle?


Yup, check out my edit.

E: For walking actually something like:
type TPathItem = record
//... path info ...
ObstaclePresent: Boolean;
Obstacle: function():Boolean;
end;

Then there is no confusion.

Coh3n

2010-07-28 17:43:44

I don't really think an ObstaclePresent is necessary to be honest. But having a TPath type would sure make things more orgainzed (and shorten the TScript record).

type
TPath = record
StartLoc: Integer;
EndLoc: Integer;
PathTo: TPointArray;
PathFrom: TPointArray;
Obstacles: array of function(Obstacle: Integer): Boolean;
end;

type
TScript = record
//...
PathInfo: TPath;
end;

Nava2

2010-07-28 18:03:39

The Obstacle argument seems useless haha.

Unless you'd rather have one function, and no array. One or the other ;)

Coh3n

2010-07-28 18:06:45

From: Nava2
The Obstacle argument seems useless haha.

Unless you'd rather have one function, and no array. One or the other ;)

Why would you need it if you have this?

function WalkTo(x, y: Integer): Boolean;
begin
for i := x to y do
begin
if (Script.WalkObstacles[i]() <> nil) then
Script.WalkObstacles[i]();
//...
end;
end;

NCDS

2010-07-28 18:10:48

From: Nava2
Yup, check out my edit.

E: For walking actually something like:
type TPathItem = record
//... path info ...
ObstaclePresent: Boolean;
Obstacle: function():Boolean;
end;

Then there is no confusion.


I quite like that idea to be honest, assuming I'm understanding it correctly.

Nava2

2010-07-28 18:21:00

From: NCDS
I quite like that idea to be honest, assuming I'm understanding it correctly.


It gives a bit more context for each path. I think thats better than having a record with everything in arrays.

Then you can do:

function walkto(x, y: Integer): boolean;
begin
for i := x to y do
with PathItem[i] do
begin
if (obstaclePresent) then

//...
end;
end;

Coh3n

2010-07-28 18:21:46

Whatever works. :p It really doesn't matter either way to me.

Sir R. M8gic1an

2010-07-29 19:17:37

I don't see the advantage of pointers. They're cool an all, but then again they never even worked that well in scar, and guessing they'll work similar in Simba you'll still be very far from OOP.

What I do like is the Obstacles idea that came up on this thread.

That's the one I find worth looking into. The pointers are just something that could look cool imo.

I don't really see how they'll make life easier on us, nor how they'll make MSI better.

~RM

Nava2

2010-07-29 20:16:19

@RM, flexibility is the main point here.

Sir R. M8gic1an

2010-07-30 05:33:39

From: Nava2
@RM, flexibility is the main point here.


This sort of Flexibility is useful when we have something like

function VEBToVEM: boolean;
function VEMToVEB: boolean;
function FEBToRM: boolean;
function RMToFEB: boolean;
function GEToYews: boolean;
function YewsToGE: boolean;

not that necessary when we have
WalkToLoc(startloc, endloc: integer): boolean;

~RM

Nava2

2010-07-30 08:47:31

From: Rasta Magician
This sort of Flexibility is useful when we have something like

function VEBToVEM: boolean;
function VEMToVEB: boolean;
function FEBToRM: boolean;
function RMToFEB: boolean;
function GEToYews: boolean;
function YewsToGE: boolean;

not that necessary when we have
WalkToLoc(startloc, endloc: integer): boolean;

~RM


Thats what I was suggesting.

Big cases are ugly, and hard to maintain.

EvilChicken!

2010-07-30 11:41:30

I'm sorry to get involved in this as a non-contributor of MSI, but I feel like I should share my view of things, having read this thread and found the original suggestion quite brilliant.

Now, I see things the way Nava2 sees them, as far as I understood from his posts. (Not saying they were hard to understand! :p Just saying I might've misunderstood something.) If you utilize pointers, I see that as a way of simply reducing the amount of code required for checks and likewise procedures, and increasing the readability and structure of mentioned procedures.
I'm actually surprised that you, RM, don't seem to quite grasp the overall usefulness of this, (absolutely no offense intended!) since you're the one who (at least for me) pinpointed how much constants play a key role in maintaining scripting efficiency and organization/structure – all in all, I believe this is somewhat comparable to having constants in many ways, one of the most important ones being the ease of maintenance on your shoulders; how much easier this would make to add changes and modifications, allowing entire locations to be added or removed while requiring fewer tweaks and changes to implement/remove mentioned location(s).

Sir R. M8gic1an

2010-07-30 16:11:21

It makes little sense to use pointers & function WalkTo(start, end); It's either one or the other.

This might make some sense for the color walks, but very little sense for reflection walking.
For our reflection walks all we do is use the same function with different paths.

Is it really worth it to have this for color walks and have the other for reflection?
Because we do have things such as
function MSI_WC_VEPoints(index: integer): TPoint;

to which we could point it. However, considering that all the walking has to 'do' certain things that are the same, if we pointed anything we'd have to be repeating code.

~RM

Coh3n

2010-07-30 23:05:38

From: Rasta Magician
This sort of Flexibility is useful when we have something like

function VEBToVEM: boolean;
function VEMToVEB: boolean;
function FEBToRM: boolean;
function RMToFEB: boolean;
function GEToYews: boolean;
function YewsToGE: boolean;

not that necessary when we have
WalkToLoc(startloc, endloc: integer): boolean;

~RM

So each script would be pointed to WalkToLoc() by default, and if there was an obstacle in the path it would be pointed to WalkToLocWithObstacle().

From: Nava2
Thats what I was suggesting.

Big cases are ugly, and hard to maintain.

I don't remember if I told you this, but after I've applied the stuff in the changes to the core thread, there will no longer be those long cases (as I wasn't a fan either).

From: Rasta Magician
It makes little sense to use pointers & function WalkTo(start, end); It's either one or the other.

This might make some sense for the color walks, but very little sense for reflection walking.
For our reflection walks all we do is use the same function with different paths.

Is it really worth it to have this for color walks and have the other for reflection?
Because we do have things such as
function MSI_WC_VEPoints(index: integer): TPoint;

to which we could point it. However, considering that all the walking has to 'do' certain things that are the same, if we pointed anything we'd have to be repeating code.

~RM

I think everyone is focusing on just the walking here, when the pointers can be used for other things as well. I don't know, walking may have been a bad example for me to show (but I liked the obstacle part of it). If we were to also use pointers for objects, I think that would be a great advandage.

program new;
{$i srl/srl.scar}

type
TScript = record
AutoObjects: function(): Boolean;
end;

procedure MSI_LoadScripts();
begin
with MSI_Scripts[SCRIPT_POWER_CHOP] do
AutoObjects := MSI_ChopInvFull();
end;

function MSI_AutoObjects(): Boolean;
var
Script: TScript;
begin
Script := MSI_Scripts[];

if (Script.AutoObjects <> nil) then
Result := Script.AutoObjects()
else
MSI_Debug();
end;

begin
end.
I think it would make the entire Mainloop.scar file more orgainzed and understandable. It also, like Nava's main point, increases flexibility tremendously as if a script requires something really specific, it can easily be done without changing other areas of the include.

E: Just an idea of what I was thinking…
[PHP]
type
TScript = record
// All relative script information
Name : string;
Runtime : Integer;
Tools : TIntegerArray;
SkillName : string;
SkillConstant: Integer; // The skill constants are in Players.scar (SRL)
Objects : TVariantArray; // The default objects to be autoed;
Items : array of TVariantArray;
BankType : TBank; // One of the attributes in the TBank set
BankConstant : Integer;
PathRefTo : TPointArray; // Not TTile array because we want it to compile without reflection
PathRefFrom : TPointArray;
PathColorTo : TIntegerArray;
PathColorFrom: TIntegerArray;

// Pointers
WalkToLoc : function(sLoc, eLoc: Integer): Boolean;
WalkToBank : function(sLoc, eLoc: Integer): Boolean;
AutoObjects: function(objects: TIntegerArray): Boolean;

// Used for progress reports; keeps track of player information
PlayerSkillLevel : Integer;
PlayerGainedExp : Integer;
PlayerLoads : Integer;
PlayerItemAmounts: array of TIntegerArray;
end;
[/PHP]

Sir R. M8gic1an

2010-07-31 06:48:06

humm. This came up before. Maybe right at the start of MSI ?

The WaitWhileX functions and so on would also need pointing to. If we're going to use pointers lets use pointers for all of them.

If everyone understands pointers I'm in favour of them. But we'll need this properly organized. I want a massive change, not just a couple of functions. I'll come back to this later.

Because this will mean we can literally port scripts.

~RM

Sir R. M8gic1an

2010-07-31 08:43:31


var
ObstaclePoints: TPointArray;
Obstacles: array of function(Where: TPoint): boolean;

//Walking
function WalkTo(StartLoc, EndLoc: TPoint): boolean;

//gatherers
function FindMSObject(Obj: TMSObject):TPoint;
function FollowMSObject(Obj: TMSObject): TPoint;
function IsMSObjectHere(Obj: TMSObject; Where: TPoint): boolean;
function WaitInvFull: boolean;

//Inv manipulators
function ManipulateInventory: boolean;
function ApplyManipulation(OnWhat: TItem): boolean;
function AwaitManipulation: boolean;

function MatchTPoint(TP1, TP2: TPoint): boolean;
begin
Result := false;

if TP1.x = TP2.x then
if TP1.y = TP2.y then
Result := true;
end;

Function MSI_LoadObstacle(Which: TPoint): boolean;
begin
case Which of
Point(): functionName();
Point(): functionName();
Point(): functionName();
end;
end;

Procedure MSI_LoadPath;
var
i, h: integer;
begin
PathTo := [...];
ObstaclePoints := [...];

for i:= 0 to High(PathTo) do
for i := 0 to High(ObstaclePoints) do
if MatchTPoint(PathTo[i], ObstaclePoints[i]) then
Obstacles[i]() := @MSI_LoadObstacle(ObstaclePoints[i]);
end;

Function MSI_WalkPath(...);
var
i: integer;
begin
for i:= 0 to High(Path) do
begin
if Obstacles[i](Path[i]) <> nil then
Obstacles[i](Path[i]);

//usual stuff here
end;

end;

The obstacle handling is a bit sketchy. Simba can case TPoints, that is one of the things I checked.

I still don't quite like using pointers. But as the SLs seem to be for it..

~RM

ZephyrsFury

2010-07-31 08:53:47

What I did in NZMM was have an array of functions for obstacles with the walking split up into "legs" between each obstacle. I'm not sure how the MSI walking system works but it seems kinda pointless to have function pointers when using reflection paths.

Sir R. M8gic1an

2010-07-31 09:04:07

From: ZephyrsFury
What I did in NZMM was have an array of functions for obstacles with the walking split up into "legs" between each obstacle. I'm not sure how the MSI walking system works but it seems kinda pointless to have function pointers when using reflection paths.


That's what I said ;)

On the post above, it's only pointing at obstacle solvers.

[actually, I do have it pointing there. My bad]

I really think the advantages & disadvantages of this will match up quite closely. Plus for pointers there's an awful lot of changing for us to do.

~RM

Coh3n

2010-07-31 11:13:35

From: Rasta Magician
That's what I said ;)

On the post above, it's only pointing at obstacle solvers.

[actually, I do have it pointing there. My bad]

I really think the advantages & disadvantages of this will match up quite closely. Plus for pointers there's an awful lot of changing for us to do.

~RM

What you wrote above, we would have to have the obstacle point a tile, would be not? And a point on the path would have to be the same as the obstacle.

Can you guys explain to me why you think it's pointless to use pointers with reflection walking? Because I really don't know why. :p

Oh, and RM, that was one of my main reasons for liking this in the first place. If done right, we can literally add the script record/constant and it's done.

Sir R. M8gic1an

2010-07-31 11:22:50

Because with reflection walking you will always just loop the path from start to end. You won't do anything different. Therefore no need for pointers as they'll all point to the same thing.

Yes, the obstacle point (or a point close by) would have to be in the path, and we'd have to assign that same point to the obstacle.

~RM

ZephyrsFury

2010-07-31 11:25:50

From: Coh3n
Can you guys explain to me why you think it's pointless to use pointers with reflection walking? Because I really don't know why. :p


It's pointless because you can just load paths for each location and have one generic walking function that walks the path regardless of the location. You only really need to create specific functions for each location if the functions are fundamentally different (for example with obstacles you might need to open a door or climb a ladder or both).

RM You don't give me time to think :(

Coh3n

2010-07-31 11:38:32

From: Rasta Magician
Because with reflection walking you will always just loop the path from start to end. You won't do anything different. Therefore no need for pointers as they'll all point to the same thing.

Yes, the obstacle point (or a point close by) would have to be in the path, and we'd have to assign that same point to the obstacle.

~RM

That's what I was trying to say, they're not always the same. Yes, 90% of the time you loop through the points, but there's the other 10% that requires something different.

//gatherers
function FindMSObject(Obj: TMSObject):TPoint;
function FollowMSObject(Obj: TMSObject): TPoint;
function IsMSObjectHere(Obj: TMSObject; Where: TPoint): boolean;
function WaitInvFull: boolean;
Why would we need all that? Each skill has it's own functions and the "last function" or MSI_ChopInvFull for example, uses all the other woodcutting functions. Would be simpler to just do:

AutoObjects := @MSI_ChopInvFull;
I think that would be a good example of a pointer where NOTHING else in the include needs to be changed for it to work.

Function MSI_LoadObstacle(Which: TPoint): boolean;
begin
case Which of
Point(): functionName();
Point(): functionName();
Point(): functionName();
end;
end;
I think that would have to return a function(): Boolean. And would an Obstacles.scar be needed for something like this? Functions for the different obstacles? Or maybe just one generic function that works for all of them?

With that post I'm guessing you were trying to avoid pointers? For walking at least. Either way, I like it. :)

Oh, and:
[PHP]
type
TPath = record
StartLoc : Integer;
EndLoc : Integer;
RefTo : TPointArray;
RefFrom : TPointArray;
ColorTo : TIntegerArray;
ColorFrom : TIntegerArray;
ObstaclePoints: TPointArray;
Obstacles : array of function(Where: TPoint): Boolean;
end;
[/PHP]

E:
From: ZephyrsFury
It's pointless because you can just load paths for each location and have one generic walking function that walks the path regardless of the location. You only really need to create specific functions for each location if the functions are fundamentally different (for example with obstacles you might need to open a door or climb a ladder or both).

RM You don't give me time to think :(

That was my whole point… Yes, most of the script would be assigned to the same function, then the ones that aren't can easily be changed. But I like RM's idea a little better right now anyway.

Also:
[PHP]
type
TScript = record
// All relative script information
Name : string;
Runtime : Integer;
Tools : TIntegerArray;
SkillName : string;
SkillConstant: Integer; // The skill constants are in Players.scar (SRL)
Objects : TVariantArray; // The default objects to be autoed;
Items : array of TVariantArray;
BankType : TBank; // One of the attributes in the TBank set
BankConstant : Integer;
PathInfo : TPath;

// Pointers
AutoObjects: function(objects: TIntegerArray): Boolean;

// Used for progress reports; keeps track of player information
PlayerSkillLevel : Integer;
PlayerGainedExp : Integer;
PlayerLoads : Integer;
PlayerItemAmounts: array of TIntegerArray;
end;
[/PHP]

Sir R. M8gic1an

2010-07-31 11:49:00

Now that we have MirrorTPA somewhere, can we get rid of RefFrom ?

I think we're better off Pointing it to LoadObstacles / SolveObstacles (a function that'll wrap the solvers), otherwise it'll be… as what it seems to me, a pain in the ass to point properly every time and we might have already solved an obstacle and just simply forget we already have that function.

~RM

Coh3n

2010-07-31 12:23:34

From: Rasta Magician
Now that we have MirrorTPA somewhere, can we get rid of RefFrom ?

I think we're better off Pointing it to LoadObstacles / SolveObstacles (a function that'll wrap the solvers), otherwise it'll be… as what it seems to me, a pain in the ass to point properly every time and we might have already solved an obstacle and just simply forget we already have that function.

~RM

Okay, so I'll see if I can come up with a semi-conclusion.

type
TPath = record
StartLoc : Integer;
EndLoc : Integer;
RefTo : TPointArray;
ColorTo : TIntegerArray;
ColorFrom : TIntegerArray;
ObstaclePoints: TPointArray;
Obstacles : TIntegerArray;
DoObstacles : array of function(Obstacle: Integer): Boolean;
end;

type
TScript = record
// All relative script information
Name : string;
Runtime : Integer;
Tools : TIntegerArray;
SkillName : string;
SkillConstant: Integer; // The skill constants are in Players.scar (SRL)
Objects : TVariantArray; // The default objects to be autoed;
Items : array of TVariantArray;
BankType : TBank; // One of the attributes in the TBank set
BankConstant : Integer;
PathInfo : TPath;

// Pointers
AutoObjects: function(objects: TIntegerArray): Boolean;

// Used for progress reports; keeps track of player information
PlayerSkillLevel : Integer;
PlayerGainedExp : Integer;
PlayerLoads : Integer;
PlayerItemAmounts: array of TIntegerArray;
end;

function MSI_DoObstacle(Which: Integer): Boolean;
begin
end;

function MSI_LoadPath(sLoc, eLoc: Integer): TPointArray;
var
i, j: integer;
Script: TScript;
ObstaclePoints: TPointArray;
begin
Script := MSI_Scripts[];

if (sLoc = Script.PathInfo.StartLoc) then
Result := Script.PathInfo.RefTo
else
if (sLoc = Script.PathInfo.EndLoc) then
Result := MSI_MirrorTPA(Script.PathInfo.RefTo);

ObstaclePoints := Script.PathInfo.ObstaclePoints;

for i := 0 to High(Result) do
for j := 0 to High(ObstaclePoints) do
if SameTPA([Result[i]], [ObstaclePoints[j]]) then
Script.PathInfo.DoObstacles[j]() := @MSI_DoObstacle(Script.PathInfo.Obstacles[j]);
end;

function MSI_WalkPath(sLoc, eLoc: Integer): Boolean
var
i: integer;
PathInfo: TPath;
Script: TScript;
begin
Script := MSI_Scripts[];
Path := MSI_LoadPath(sLoc, eLoc);

for i := High(Path) downto 0 do
begin
if (Script.PathInfo.DoObstacles[i]() <> nil) then
Script.PathInfo.DoObstacles[i]();

//usual stuff here
end;
end;
I have a feeling that the way I used the DoObstacles pointer wouldn't work though…

Coh3n

2010-08-02 11:56:04

I was just thinking, I don't think we even need the DoObstacle pointers.

function MSI_WalkPath(sLoc, eLoc: Integer): Boolean
var
i: integer;
PathInfo: TPath;
Script: TScript;
begin
Script := MSI_Scripts[];
Path := MSI_LoadPath(sLoc, eLoc);

for i := High(Path) downto 0 do
begin
ObstaclePoints := Script.PathInfo.ObstaclePoints;
for j := 0 to High(ObstaclePoints) do
if SameTPA([Result[i]], [ObstaclePoints[j]]) then
MSI_DoObstacle(Script.PathInfo.Obstacles[j]);

//usual stuff here
end;
end;

Nava2

2010-08-02 13:51:08

From: Coh3n
I was just thinking, I don't think we even need the DoObstacle pointers.

function MSI_WalkPath(sLoc, eLoc: Integer): Boolean
var
i: integer;
PathInfo: TPath;
Script: TScript;
begin
Script := MSI_Scripts[];
Path := MSI_LoadPath(sLoc, eLoc);

for i := High(Path) downto 0 do
begin
ObstaclePoints := Script.PathInfo.ObstaclePoints;
for j := 0 to High(ObstaclePoints) do
if SameTPA([Result[i]], [ObstaclePoints[j]]) then
MSI_DoObstacle(Script.PathInfo.Obstacles[j]);

//usual stuff here
end;
end;


How can you make *every* obstacle be the same actions etc. Some will be climbing under a wall, others over a fence, opening a door, climbing a ladder, they aren't the same.

Coh3n

2010-08-02 14:41:29

From: Nava2
How can you make *every* obstacle be the same actions etc. Some will be climbing under a wall, others over a fence, opening a door, climbing a ladder, they aren't the same.

Well I'm assuming all we would have to do is find the obstacle and click the proper uptext. Unless I'm missing something, we can have different object records for each obstacle.

ZephyrsFury

2010-08-03 00:13:27

From: Coh3n
Well I'm assuming all we would have to do is find the obstacle and click the proper uptext. Unless I'm missing something, we can have different object records for each obstacle.


In theory its all just finding and clicking objects but in practice it is rarely so. If you try to have one generic function you'll eventually be adding case statements everywhere creating a monster function that should be broken up into individual functions anyway - hence the reason for function pointers.

Sir R. M8gic1an

2010-08-03 05:37:18

From: ZephyrsFury
In theory its all just finding and clicking objects but in practice it is rarely so. If you try to have one generic function you'll eventually be adding case statements everywhere creating a monster function that should be broken up into individual functions anyway - hence the reason for function pointers.


Our MS object finding function is pretty much.. awesome, in all honesty :p

If all obstacles are related to clicking an object.. we could have an obstacle record.

AtObstacle
TheObstacle
PastObstacle

We'd need to keep in mind color & ref.

hummmmmmmm. This is sounding interesting to me.

~RM

Coh3n

2010-08-03 11:23:34

From: ZephyrsFury
In theory its all just finding and clicking objects but in practice it is rarely so. If you try to have one generic function you'll eventually be adding case statements everywhere creating a monster function that should be broken up into individual functions anyway - hence the reason for function pointers.

What can be different though? I mean, anything that's different between the objects is stored in it's record.

Nava2

2010-08-03 11:30:41

Zeph is correct, trying to over-generalize things only leads to head aches.

ZephyrsFury

2010-08-03 11:46:42

From: Coh3n
What can be different though? I mean, anything that's different between the objects is stored in it's record.


For example.. climbing ladders and opening doors (two things I've had experience with). Here are a couple cases:

When should the functions return true? For a door object, the function OpenDoor should return true when the object is found and successfully interacted with OR if the object isn't found (indicating possibly that the door is already opened). With the ladder, obviously the function should only return true when you've successfully climbed it. If the ladder object cannot be found then something's wrong and the func should result false.

Detecting whether the object is successfully interacted with.. door: perhaps check if the object still exists. Ladder: need to find out if climbing a ladder changes your tile position, if it does then you need to check if your position has changed. If it doesnt then you need some other check since the object still exists at that tile.

Where the mouse should click in relation to the object tile? Doors: click should be on the edges of the tile since doors are placed on tile edges. Ladders are generally in the middle. Special case is the Falador side of the ladders to the mining guild. There are 4 ladders but if you try click one of the four ladder tiles in the centre you won't find the uptext since the interactable area is towards the edges and in the centre tile between the 4.

Other things: obstacles requiring interactions with NPCs instead, requiring chatting after clicking objects, Colour and Reflection in one function?.

tl;dr too many things to consider for one function.

Coh3n

2010-08-03 12:03:37

From: ZephyrsFury
For example.. climbing ladders and opening doors (two things I've had experience with). Here are a couple cases:

When should the functions return true? For a door object, the function OpenDoor should return true when the object is found and successfully interacted with OR if the object isn't found (indicating possibly that the door is already opened). With the ladder, obviously the function should only return true when you've successfully climbed it. If the ladder object cannot be found then something's wrong and the func should result false.

Detecting whether the object is successfully interacted with.. door: perhaps check if the object still exists. Ladder: need to find out if climbing a ladder changes your tile position, if it does then you need to check if your position has changed. If it doesnt then you need some other check since the object still exists at that tile.

Where the mouse should click in relation to the object tile? Doors: click should be on the edges of the tile since doors are placed on tile edges. Ladders are generally in the middle. Special case is the Falador side of the ladders to the mining guild. There are 4 ladders but if you try click one of the four ladder tiles in the centre you won't find the uptext since the interactable area is towards the edges and in the centre tile between the 4.

Other things: obstacles requiring interactions with NPCs instead, requiring chatting after clicking objects, Colour and Reflection in one function?.

tl;dr too many things to consider for one function.

That's good enough for me. :p

I obviously didn't think about all that stuff (probably comes from having no experience in that area).

So we'd be best off sticking with the DoObstacles pointer? In this case I would assume we would need an Obstacles.simba to hold all these functions?

Coh3n

2010-08-21 12:39:25

Committed the AutoObjects pointer, and the obstacle discussion can be continued here.