PDA

View Full Version : Custom Classes!


Novo
12-06-2007, 02:37 AM
Yea... I was talking with Stan, and I was like 'you can't make custom classes using the new operator'... And it dawned: A function call is what you need. Taking inspiration from Java, I created a custom-class. :)

class manager: (DB: Class )

public function createClass( className, classes )
{
if ( (@ className ) != null )
(@ className ).destroy();

// Create what it means to be an object...
echo("Creating class" SPC className );
temp.newClass = new TStaticVar( (@className) );
temp.newClass.join( "test_custom_class" );
temp.newClass.classes = classes;

// Don't let the garabe collecter get this!
this.classes.add( temp.newClass );
}

public function getClasses()
{
return this.classes;
}


custom class script: (test_custom_class)

public function newInstance( objectName )
{
if ( (@ objectName ) != null )
(@ objectName ).destroy();

temp.newInstance = new TStaticVar( @objectName );
for ( temp.cjoin: this.classes )
{
temp.newInstance.join( temp.cjoin );
}

temp.newInstance.class = this;
return temp.newInstance;
}


Testing Class: (test_tnode)

/**
* Nodes Interface for PathFinder
*
* (+) void connect( Node node, ... );
* (+) void disconnect( Node nodes );
* (+) Node[] getNodes();
* (+) Node[] findPath( Node goal );
**/

/**
* This connects a node to the node-list.
*
* @param node Node, any object that could be treated as a Node.
* If used to connect afterwards, add Node interface!
**/
public function connect()
{
for ( temp.node: params )
{
if ( temp.node == null )
return;
if ( temp.node in this.nodes )
return;

this.nodes.add( temp.node );
}
}

/**
* This removes a node to the node-list.
*
* @param node, ... Node, any object that could be treated as a Node.
**/
public function disconnect( node )
{
this.nodes.remove( node );
}

/**
* This obtains the nodes that are currently connected to the object.
*
* @return Node[] List of nodes attached to object
**/

public function getNodes()
{
return this.nodes;
}

/**
* This calculates the shortest distance to a particular node.
*
* @return Node[] An ordered list of the nodes that need to be traveled
* to reach given destination.
**/
public function findPath( endNode )
{
temp.nodeList.add( {this, new[0]} );
temp.nodeIndex = 0;
while ( temp.nodeList.size() > temp.nodeIndex )
{
temp.node = temp.nodeList[ temp.nodeIndex ][0];
temp.nodePath = temp.nodeList[ temp.nodeIndex ][1];
temp.nodePath.add( temp.node );
if ( temp.node == endNode )
return temp.nodePath;

for ( temp.subnode: node.getNodes() )
{
if ( temp.subnode in temp.nodeList )
continue;

temp.nodeList.add( { temp.subnode, temp.nodePath } );
}
temp.nodeIndex ++;
}

return null;
}


Example of Usage:

function onCreated()
{
Class.createClass( "TNode", {"test_tnode"} );

node1 = TNode.newInstance("N1");
node2 = TNode.newInstance("N2");
node3 = TNode.newInstance("N3");
node4 = TNode.newInstance("N4");

node1.connect( node2 );
node2.connect( node3, node4 );
node3.connect( node4 );

nodePath = node1.findPath( node4 );

echo("Path:");
for ( node: nodePath )
echo( node.name );
}

/** Output **
The script of NPC Class has been updated by Novo
Creating class TNode
Path:
N1
N2
N4
**/



:)

MrAnonymous_P2P
12-06-2007, 02:54 AM
Shouldn't this be in code gallery?

Inverness
12-06-2007, 03:18 AM
Yea... I was talking with Stan, and I was like 'you can't make custom classes using the new operator'
The new operator can be used with an object name or the name of an object type, and when used with an existing object it copies all variables to the new object including this.joinedclasses, causing the classes in the copied object to be joined to the new object.

public function onCreated() {
temp.i = 0;
this.scriptlogmissingfunctions = false;
this.types = null;
// MudObjects
maketype("MudObject", null, {"util_triggerall", "util_schedulefunction", "type_mudobject"});
maketype("MudPlayer", TMudObject, {"type_mudplayer"});
maketype("MudItem", null, {"util_schedulefunction", "type_muditem"});
// Dialog
maketype("DialogTopic", null, {"type_dialogtopic"});
maketype("DialogResponse", null, {"type_dialogresponse"});
maketype("DialogCondition", null, {"type_dialogcondition"});
// Misc
maketype("IniFile", null, {"type_inifile"});
maketype("DataFile", null, {"type_datafile"});
maketype("Rectangle", null, {"type_rectangle"});
this.created = true;
}
public function maketype(typename, super, classes) {
temp.i = 0;
if (makevar("T"@typename) != null) {
makevar("T"@typename).destroy();
}
this.(@ "type_" @ typename) = new TStaticVar("T"@typename);
if (super.type() == 2) {
this.(@ "type_" @ typename).joinedclasses = super.joinedclasses;
}
for (i: classes) {
this.(@ "type_" @ typename).join(i);
}
if (this.types.index("T"@typename) < 0) {
this.types.add("T"@typename);
}
}


// Use
function onCreated() {
temp.obj = 0;

obj = new TIniFile();
obj.load("data/news.ini");
// More Stuff
obj.destroy();

obj = new TRectangle();
obj.x = 20;
obj.y = 20;
obj.w = 32;
obj.h = 32;
if (obj.contains(player.x, player.y))
echo("Yep!");
else
echo("Nope");
obj.destroy();
}

Novo
12-06-2007, 04:19 AM
...

Hrm! That's a bit weird. Ohwell. Either way. :)

Inverness
12-06-2007, 12:50 PM
Though I'd like if there was a function called in the class when it was joined and had to be completed before the next class could be joined.

onCreated does not work like this :(

coreys
12-06-2007, 04:07 PM
Osnap, Inver beat you to it, Novo. :(

Novo
12-06-2007, 10:19 PM
Osnap, Inver beat you to it, Novo. :(

O,o; We're racing?

Inverness
12-06-2007, 11:57 PM
O,o; We're racing?
Racing is fun, yes?

coreys
12-07-2007, 12:44 AM
Racing is fun, yes?

I agree!

Novo
12-09-2007, 05:46 PM
onCreated does not work like this :(


public function newInstance( param, objectName )
{
if ( objectName != "" )
if ( (@ objectName ).type() == 2 )
(@ objectName ).destroy();

// Initialize Class
if ( objectName == "" )
temp.newInstance = new TStaticVar();
else temp.newInstance = new TStaticVar( @objectName );

temp.newInstance.class = this;
temp.newInstance.join( ("class_"@ this.name).lower() );

// Initialize Object
if ( this.name in temp.newInstance.getfunctions() )
temp.newInstance.(@ this.name )( param );

return temp.newInstance;
}


:) I made a turnaround for that onCreated problem. Basically, the newInstance() would call the constructor for the class ( thus, TNode )


public function TNode() { foo; }


Makes sure that the initialize variables are initialized immediately.

Such as:

function onCreated()
{
array = TMap.newInstance( {{"Test3", "333"}} );
array.put("Test", 123);
array.put("Test2", 123);
array.put("Test", 321);
echo( array.toString() ); // output: "Test3,333","Test,321","Test2,123"
}


EDIT: I'm thinking of having an inheritance system working out... So one could probably do an object.class.instanceof( otherclass )... Something along the lines of:

public function instanceOf( class )
{
if ( this == class )
return true;
// for ( superClass: superClasses )
// if ( superClass.instanceOf( class ) )
// return true;
return false;
}

Inverness
12-09-2007, 07:20 PM
You're overdoing it as far as Graal goes :P

I tried doing something like that for my Mud system and making it modular and stuff, but its easier to just make a class that does everything at once.

Novo
12-09-2007, 07:28 PM
I actually went ahead and did it anyways... So I added inheritance and static functions... :: hums ::

Bah. For some reason, I can't sent it over forums. It says there's a bad request that the server can't understand.

napo_p2p
12-09-2007, 07:33 PM
I actually went ahead and did it anyways... So I added inheritance and static functions... :: hums ::

Bah. For some reason, I can't sent it over forums. It says there's a bad request that the server can't understand.

If you have percent sign in a post, you get a bad request error.

xXziroXx
12-09-2007, 08:54 PM
I actually went ahead and did it anyways... So I added inheritance and static functions... :: hums ::

Bah. For some reason, I can't sent it over forums. It says there's a bad request that the server can't understand.

Use "Quick Reply" instead, never got a Bad Request with that. :)

Novo
12-09-2007, 08:59 PM
Custom Classes (Database):

function onCreated()
{
createClass( "TObject" );
createClass( "TMap", TObject );
createClass( "TMapMod", TMap );
createClass( "TNode", TObject );
}

function createClass( className, superClass )
{
if ( "class" in serverr.debug )
echo("Creating class" SPC className );

if ( (@ className ).type() == 2 )
(@ className ).destroy();

// Create class object
temp.newClass = new TStaticVar( (@className) );
temp.newClass.super = superClass;

// Add Static Functions
temp.classes = { temp.newClass };
if ( superClass != null )
temp.classes.addarray( superClass.getClasses() );

for ( temp.class: temp.classes )
temp.newClass.join( ("class_"@ temp.class.name @"_static").lower() );
temp.newClass.join( "class_tclass" );

// Don't let the garabe collecter get this!
this.classes.add( temp.newClass );
return temp.newClass;
}

public function getClasses()
{
return this.classes;
}


class_tclass (Class):

/** Class object **
(+) Class[] getClasses();
(+) Class getSuperclass();
(+) String getName();
(+) String toString();
(+) Object newInstance( objectName );
**/

public function getName()
{
return this.name;
}

public function toString()
{
return getName();
}

public function newInstance( param, objectName )
{
if ( objectName != "" )
if ( (@ objectName ).type() == 2 )
(@ objectName ).destroy();

// Initialize Class
if ( "class" in serverr.debug )
echo("Initializing class" SPC this.name );

if ( objectName == "" )
temp.newInstance = new TStaticVar();
else temp.newInstance = new TStaticVar( @objectName );
temp.newInstance.class = this;

temp.classes = getClasses();
for ( temp.class: temp.classes )
{
if ( "class" in serverr.debug )
echo("Joining gClass" SPC temp.class.getName() );
temp.newInstance.join( ("class_"@ temp.class.getName() ).lower() );
}

// Call constructor!
for ( temp.class: temp.classes )
{
if ( temp.class.getName() in temp.newInstance.getfunctions() )
{
temp.newInstance.(@ temp.class.getName() )( param );
break;
}
}


return temp.newInstance;
}

public function getClasses()
{
temp.classes = {this};

temp.super = getSuperclass();
if ( temp.super != null )
temp.classes.addarray( temp.super.getClasses() );

return temp.classes;
}

public function getSuperclass()
{
return this.super;
}


class_tobject (Class):

/** General Object **
(+) void TObject();

(+) boolean instanceOf( Class class );
(+) String toString();
(+) Class getClass();
**/

public function TObject()
{
if ( "class" in serverr.debug )
echo( "Initialized Object" SPC toString() );
}

public function instanceOf( class )
{
return ( class in getClass().getClasses() );
}

public function toString()
{
return this.name @"-"@ this.class.getName();
}

public function getClass()
{
return this.class;
}


And... As a bonus class to this great deal, TMap! (Call now, and get TNode for free!) Only fifty-five payments of 9.99$:

/** TMap inherits TObject **
// Constructor
(+) void TMap( String[][] contents );

// Object Manipulation
(+) Object get( String key );
(+) void put( String key, Object value );
(+) void putAll( String[][] contents );
(+) void removeKey( String key ); * can't override .remove
(+) void clearMap();

// Testing
(+) boolean containsKey( String key );
(+) boolean containsValue( Object value );

(+) String[] keySet();
(+) Object[] values();

(+) int mapSize();
(+) boolean isEmpty();

(+) String[][] toArray();
**/

public function TMap( initialContents )
{
TObject();
if ( this.init )
return;

this.init = true;
putAll( initialContents );
}

public function putAll( newContents )
{
for ( temp.content: newContents )
this.put( temp.content[0], temp.content[1] );
}

public function get( key )
{
for ( temp.content: this.contents )
{
if ( temp.content[0] == key )
return temp.content[1];
}

return null;
}

public function put( key, value )
{
for ( temp.content: this.contents )
{
if ( temp.content[0] == key )
{
temp.content[1] = value;
return;
}
}

this.contents.add( {key, value} );
return;
}

public function removeKey( key )
{
for ( temp.i = 0; temp.i < this.contents.size(); temp.i ++ )
{
temp.content = this.contents[ temp.i ];
if ( temp.content[0] == key )
{
this.contents.delete( temp.i );
return;
}
}
}

public function clearMap()
{
this.contents = "";
}

public function mapSize()
{
return this.contents.size();
}

public function isEmpty()
{
return (this.size() == 0);
}

public function containsKey( key )
{
for ( temp.content: this.contents )
if ( temp.content[0] == key )
return true;
return false;
}

public function containsValue( value )
{
for ( temp.content: this.contents )
if ( temp.content[1] == value )
return true;
return false;
}

public function values()
{
temp.values = new[0];
for ( temp.content: this.contents )
temp.values.add( temp.content[1] );
return temp.values;
}

public function keySet()
{
temp.keys = new[0];
for ( temp.content: this.contents )
temp.keys.add( temp.content[0] );
return temp.keys;
}

public function toArray()
{
return this.contents;
}

Inverness
12-09-2007, 10:13 PM
If we had support for global functions the way I wanted (including Control-NPC in the function lookup), it would be a simple and easy deal to have global functions (temp.var = TObjectType();) to return the new object instance.

Novo
12-09-2007, 10:32 PM
If...

Anyhow...

I made an addition to my TMap set. For those of you who want to use it, I've made a static function for it:

class_tmap_static (Class)

public function merge( map1, map2, mergeRules )
{
// Sanity Check
if ( !map1.instanceOf( TMap ) || !map2.instanceOf( TMap ))
{
echo("Input aren't TMaps!");
return null; // Force programmer to input CORRECT Data!
}

// Change Merger to supplied one
temp.oldMerger = this.mergeValue;
if ( mergeRules != null )
this.mergeValue = mergeRules;

// Copy first Map to a new map
temp.sum = this.newInstance( map1.toArray() );
temp.keys = temp.sum.keySet();

// Add second map to new map
temp.mapSet = map2.toArray();
for ( temp.mapValue: temp.mapSet )
{
// If new map contains given key
if ( temp.mapValue[0] in temp.keys )
{
// Merge them together
temp.newValue = mergeValue(
temp.mapValue[0], // key
temp.mapValue[1], // val1
temp.sum.get( temp.mapValue[0] ) // val2
);

temp.sum.put( temp.mapValue[0], temp.newValue );
} else {
// Otherwise, put second map data to the new map.
temp.sum.put( temp.mapValue[0], temp.mapValue[1] );
}
}

// Revert back to old merger
this.mergeValue = temp.oldMerger;

return temp.sum;
}

function mergeValue( key, val1, val2 )
{ // Default
// val1 + val2 should be the same as val2 + val1.
return (val1 + val2);
}


Example of Usage:

function onCreated()
{
mod1 = TMap.newInstance({{"a",3}, {"b", 1}} );
mod2 = TMap.newInstance({{"a",2}, {"b", 1}, {"c", 1}} );

temp.merger = function( key, val1, val2 ) {
switch ( key )
{
case "a":
return val1 * val2;
default:
return val1 + val2;
}
};

mod3 = TMap.merge( mod1, mod2, temp.merger );
echo( mod3.toArray() ); // "a,6","b,2","c,1"
}

Inverness
12-09-2007, 10:37 PM
Anyhow...Too complex for average use.

Novo
12-09-2007, 10:53 PM
Too complex for average use.

But Powerful for those who know how to use it. Additionally, the merger comes with a default way of merging. It isn't necessary to define your own function, but the power is there if you do!


function onCreated()
{
mod1 = TMap.newInstance({{"a",3}, {"b", 1}} );
mod2 = TMap.newInstance({{"a",2}, {"b", 1}, {"c", 1}} );

mod3 = TMap.merge( mod1, mod2 );
echo( mod3.toArray() ); // "a,5","b,2","c,1"
}


Simple for those who don't need more.

Inverness
12-09-2007, 11:31 PM
But Powerful for those who know how to use it. Additionally, the merger comes with a default way of merging. It isn't necessary to define your own function, but the power is there if you do!


function onCreated()
{
mod1 = TMap.newInstance({{"a",3}, {"b", 1}} );
mod2 = TMap.newInstance({{"a",2}, {"b", 1}, {"c", 1}} );

mod3 = TMap.merge( mod1, mod2 );
echo( mod3.toArray() ); // "a,5","b,2","c,1"
}


Simple for those who don't need more.
Can you tell me an instance where it would be used in-game?

Novo
12-09-2007, 11:37 PM
Sure... Phone-Address look-up. In Era.

Phones.phoneMap = TMap.newInstance();

// In various locations around the world
Phones.phoneMap.put("553-4234", this );


// To phone...
otherPhone = Phones.phoneMap.get( "553-4234" );
otherPhone.chat = "*ring* *ring*";


Merger...
Item System:

items = TMap.newInstance();
items.put( itemID, {quant, state});

merger = function( key, val1, val2 ){ return {val1[0] + val2[0], val1[1] || val2[1]}; }
items = TMap.merge( items, TMap.newInstance( {{ itemID, quant, 0 }}, merger );


... There are many situations that it could come up.

What I use it for is to have a cumulative effects from the clothing that the player uses.
For instance, let's say 'Speed'...

Special Boots = TMap.newInstance( {{"Speed", 5}});
Other Clothing = TMap.n... ...

mods = playerMods;
mods = TMap.merge( mods, racialMods );
for ( clothes: all worn clothes )
mods = TMap.merge( mods, clothes.mods );

player.speed = mods.get("Speed");


This is done FOR-ALL possible (and future) attributes:


temp.modList = temp.mod.toArray();
for ( temp.mod: temp.modList )
clientr.(@ temp.mod[0] ) = temp.mod[1];

Inverness
12-10-2007, 12:49 AM
Sure... Phone-Address look-up. In Era.That may 'work' but using a specialized function is much simpler and to the point.
What I use it for is to have a cumulative effects from the clothing that the player uses.I just scan equipped items in the mud object and add their affects to the player's.

You're really over-complicating things that are simple to do with regular scripts. Thats not a good way to bring new scripters into the scene.

Novo
12-10-2007, 01:05 AM
That may 'work' but using a specialized function is much simpler and to the point.
I just scan equipped items in the mud object and add their affects to the player's.

You're really over-complicating things that are simple to do with regular scripts. Thats not a good way to bring new scripters into the scene.

Inverness, I've provided quite a dynamic way to do a variety of things. If you don't appreciate it for whatever reason you have (which seems to be whatever you can seem to think of), then that's that. Otherwise... There are MANY ways to skin a cat. This is one of them...

I don't think introducing new programmers to concepts such as these will help... But alternatively, for those in the know, these techniques could be used with a wide range of successful usage. Ultimately, by my publishing the code, I didn't make it ANY HARDER to learn to script. In fact, that wasn't even my targeted audience. (Additionally, new programmers could learn by example, so they might not see the full utility, but something like that could let them see how reflective programming could be done )

Whether it is overcomplicating something, or providing a bigger re-usability... It doesn't matter that much. Sure, some things just need a little function to work. Others will need more. And in the end, everything can be hard-coded as one massive monolith. In fact, you could program Graal in ONE FUNCTION.

Now, if you want to argue the value of TMap... I just provided it as a quick freebie and numerous incidents it could be used. If you're debating about Class System... I think you would already be in a level where you can use it if you considered that it is beneficial to use it in the first place. I provided quite a bit of flexibility.

Ultimately, I AM SORRY FOR GIVING YOU FREE CODE, go cry me a river. ( I refuse to feed your troll habits any further. )

cbk1994
12-10-2007, 01:21 AM
I AM SORRY FOR GIVING YOU FREE CODE

You should be!

Inverness
12-10-2007, 02:12 AM
<snip>My issue is because I did exact same thing about a year ago and found that it wasted too much time and CPU making things super flexible and modular rather than just scripting it to do what it needs to do in less time.

Though it seems our situations are different if you don't have something you need to be working on and are just scripting for fun. Though, if you do have something you need to do with this all (like making the system for a server) I wouldn't suggest such things.

I'm just trying to save you from wasting time overdoing it :P, redesigning systems and such can kill a server under construction.
You should be!
Go away, the grown-up scripters are talking now. :p

coreys
12-10-2007, 03:55 AM
Go away, the grown-up scripters are talking now. :p

But...he...wasn't making any sort of scripting comment. ._.

Inverness
12-10-2007, 05:17 AM
But...he...wasn't making any sort of scripting comment. ._.It wouldn't be far off. :D
You're supposed to nip it in the bud. *Shining aura of pure awesome*

Kyranki
12-10-2007, 05:42 AM
*Shining aura of pure awesome*

I WANT ONE! D:

coreys
12-10-2007, 06:22 AM
I WANT ONE! D:

You'll never have one.

Dan
12-10-2007, 05:34 PM
Go away, the grown-up scripters are talking now. :p

Hi

Crow
12-10-2007, 08:09 PM
Hi

Didnt you read what he said? ;)

Inverness
12-10-2007, 11:22 PM
Didnt you read what he said? ;)Perhaps he is a super ninja-scripter whos talent has yet to be revealed.

Kyranki
12-11-2007, 12:24 AM
Perhaps he is a super ninja-scripter whos talent has yet to be revealed.

Pffft. Urban Legend.

cbk1994
12-11-2007, 12:55 AM
Go away, the grown-up scripters are talking now. :p


if ( weapon is fired )
shoot bullet at other players;


i am 1337 now ?

Novo
12-11-2007, 01:21 AM
Welcome, brothers, to the secret thread of elite scripters! I've got some tea and biscuits on the table.

Hi Dan! Show us your 1337 skillz! I'm sure Inverness is no match to your prowess.

Inverness
12-11-2007, 02:37 AM
Welcome, brothers, to the secret thread of elite scripters! I've got some tea and biscuits on the table.

Hi Dan! Show us your 1337 skillz! I'm sure Inverness is no match to your prowess.My true power has yet to be revealed.
Pffft. Urban Legend.
No, I don't think Urban is one.

Kyranki
12-11-2007, 04:51 AM
No, I don't think Urban is one.

Ohnoes, I made a syntaxing error.

coreys
12-11-2007, 07:29 AM
My true power has yet to be revealed.

osht, inver can go super sayan 5

Crow
12-11-2007, 02:02 PM
Perhaps he is a super ninja-scripter whos talent has yet to be revealed.

Lets just not talk about it. Might hurt him.