Graal Forums  

Go Back   Graal Forums > Development Forums > NPC Scripting
FAQ Members List Calendar Today's Posts

Reply
 
Thread Tools Search this Thread Display Modes
  #1  
Old 01-01-2011, 10:43 PM
AlexanderK AlexanderK is offline
Registered User
AlexanderK's Avatar
Join Date: Mar 2006
Location: Germany
Posts: 79
AlexanderK is on a distinguished road
Send a message via MSN to AlexanderK
function not found in script

Hi

I'm trying to code an Inventory with GuiControl for my SQL-based Item system, but I'm running into a problem.

I want to make a Combobox, that has different numbers of rows depending on how many categories of items the player has.

NPC Code:

Inventory_Categories.clearrows();
temp.categories = player.getCategories();
for (temp.i=0; temp.i < temp.categories.size(); temp.i++) {
Inventory_Categories.addrow(temp.i,temp.categories[temp.i][0]);
}
Inventory_Categories.setSelectedRow(0);



that's my getCategories() function:
NPC Code:

public function getCategories(){
temp.categories = requestSQL("SELECT DISTINCT category FROM 'player_item' WHERE account='" @player.account@ "'",true);
if(!temp.categories.completed) {
waitfor(temp.categories,"onReceiveData",60);
}
return temp.categories.rows;
}



That's what the F2-Log says.
Quote:
GraalScript: Function Player AlexanderK.getCategories not found in script of Weapon -Inventory
I just don't see what's wrong. Are weapons not allowed to access player.-functions?

I know the function works, as this NPC works:

NPC Code:
 //#Clientside
function onCreated() {
this.setshape(1,32,64);
this.chat="Touch me to find out how many categories you have";

}
function onPlayerTouchsMe() {
this.chat=player.getCategories().size() @ " , first category: " @ player.getCategories()[0][0] ;
}



I hope someone can help me.
Reply With Quote
  #2  
Old 01-01-2011, 10:45 PM
Skyld Skyld is offline
Script-fu
Skyld's Avatar
Join Date: Jan 2002
Location: United Kingdom
Posts: 3,914
Skyld has much to be proud ofSkyld has much to be proud ofSkyld has much to be proud ofSkyld has much to be proud ofSkyld has much to be proud ofSkyld has much to be proud of
Send a message via AIM to Skyld
If you are calling the function from the clientside then it must be in the clientside part of the player class, and you probably should join the player class clientside to the player just to be certain. You can't call a serverside function in the player from the clientside.
__________________
Skyld
Reply With Quote
  #3  
Old 01-01-2011, 10:49 PM
cbk1994 cbk1994 is offline
the fake one
cbk1994's Avatar
Join Date: Mar 2003
Location: San Francisco
Posts: 10,718
cbk1994 has a reputation beyond reputecbk1994 has a reputation beyond reputecbk1994 has a reputation beyond reputecbk1994 has a reputation beyond reputecbk1994 has a reputation beyond reputecbk1994 has a reputation beyond reputecbk1994 has a reputation beyond reputecbk1994 has a reputation beyond reputecbk1994 has a reputation beyond reputecbk1994 has a reputation beyond repute
Send a message via AIM to cbk1994
"//#Clientside" should be all caps, not sure if it matters but it really ought to be.

getCategories looks like a serverside function so you have to trigger to the serverside part of the script, then trigger back to clientside.

In order to do player.getCategories, it would have to be in a class joined to the player. You would still have to use it serverside.

edit: skyld beat me to it
__________________
Reply With Quote
  #4  
Old 01-01-2011, 11:35 PM
AlexanderK AlexanderK is offline
Registered User
AlexanderK's Avatar
Join Date: Mar 2006
Location: Germany
Posts: 79
AlexanderK is on a distinguished road
Send a message via MSN to AlexanderK
Thanks for the quick response, you two
Quote:
Originally Posted by cbk1994 View Post
"//#Clientside" should be all caps, not sure if it matters but it really ought to be.
So that's why the simple script I used to test getCategories() worked, it wasn't Clientside but serverside.

getCategories looks like a serverside function so you have to trigger to the serverside part of the script, then trigger back to clientside.

In order to do player.getCategories, it would have to be in a class joined to the player. You would still have to use it serverside.
[/QUOTE]
That's how I've done it.
Quote:
Originally Posted by cbk1994 View Post
getCategories looks like a serverside function so you have to trigger to the serverside part of the script, then trigger back to clientside.
So do I have to use triggeraction? Is there no easier way to pass a variable vom Serverside to Clientside?
Something like this would be nice...
NPC Code:
 function getLocalCategories() {
return player.getCategories();
}
//#CLIENTSIDE
function onCreated() {
this.setshape(1,32,64);
this.chat="Touch me to find out how many categories you have";

}
function onPlayerTouchsMe() {
temp.categories = this.getLocalCategories();
this.chat=temp.categories.size() @ " , " @ temp.categories[0][0] ;
}


Or do I have to use triggeraction? I never used it, as I'm pretty new to Graalscript.
In the wiki, triggeraction is declared as triggeraction(float x, float y, str eventname, params...) . Can I even use arrays for the params?
Reply With Quote
  #5  
Old 01-01-2011, 11:43 PM
cbk1994 cbk1994 is offline
the fake one
cbk1994's Avatar
Join Date: Mar 2003
Location: San Francisco
Posts: 10,718
cbk1994 has a reputation beyond reputecbk1994 has a reputation beyond reputecbk1994 has a reputation beyond reputecbk1994 has a reputation beyond reputecbk1994 has a reputation beyond reputecbk1994 has a reputation beyond reputecbk1994 has a reputation beyond reputecbk1994 has a reputation beyond reputecbk1994 has a reputation beyond reputecbk1994 has a reputation beyond repute
Send a message via AIM to cbk1994
You have to use triggers unfortunately.

See if this post helps:

Quote:
Originally Posted by cbk1994 View Post
There are essentially two different ways you script: on serverside, or on clientside. If a script is serverside, it means that the NPC-server interprets and performs the code. The advantage to this is that you know the code can't be tamperered with. If the code is clientside, it means that it is ran on the computer of the player. This has the advantage of being faster and not requiring communication with the server, but has the disadvantage of being less secure.

Since serverside is not performed for a specific player it cannot display interface graphics (HUDs, etc). It also can't handle player chat events, among others.

To communicate between the server and the client you use something called a trigger. In the past this was accomplished with the triggerAction function, but now it's standard practice to use triggerServer and triggerClient. Simply enough, triggerServer is used to send a "trigger", or a message, from clientside (a player's computer) to the NPC-server. Similarly, triggerClient is used to send a "trigger" from the NPC-server to a player's computer.

The simplest trigger from clientside to server would work like so:

PHP Code:
function onActionServerSide() {
  echo(
"Ping received!");
}

//#CLIENTSIDE
function onCreated() {
  
triggerServer("gui"this.namenull);

In your case you would want to send the player's chat serverside. The onPlayerChats event is called on clientside whenever the player chats.

PHP Code:
//#CLIENTSIDE
function onPlayerChats() {
  
// code

You can then check if the player's chat starts with "/copy" by using the string function str.starts(str). This would be "true" if the string starts with the parameter given.

PHP Code:
//#CLIENTSIDE
function onPlayerChats() {
  if (
player.chat.starts("/copy")) {
    
// code
  
}

Now, you need to send a trigger to the server with the triggerServer command. triggerServer and triggerClient both have three parameters (two on the latest beta of Graal or for triggerClient): script type, script name, param1[, param2...].]

The script types that you can trigger are "gui" or "weapon", which both trigger a weapon script. Scripters have their own personal preference on which to use, but it doesn't really matter. The other script type is "npc", which triggers a database NPC. If you don't know what that is, don't worry about it yet.

Adding the trigger code would look like so:

PHP Code:
//#CLIENTSIDE
function onPlayerChats() {
  if (
player.chat.starts("/copy")) {
    
triggerServer("gui"this.namenull);
  }

this.name is simply referring to the current name of the weapon. It's generally preferred to use this instead of typing the weapon name in case the name were to change.

Then, you would need to "tokenize" the player's chat. This is the same as the explode function found in PHP and other languages. It splits the string into different parts at the "delimiter". You can specify a custom delimiter for str.tokenize(str delimiter), but in this case there is no need to.

PHP Code:
//#CLIENTSIDE
function onPlayerChats() {
  if (
player.chat.starts("/copy")) {
    
temp.tokens player.chat.tokenize();
    
triggerServer("gui"this.nametokens);
  }

Now you just need to build the serverside portion of the script. This part of the script will need to identify the command given, identify the player wanted, and the property to copy. You would start by adding the onActionServerSide() event. This is always called when using triggerServer. The parameter you specified in the trigger ("tokens") will be in the first parameter for that function.

PHP Code:
function onActionServerSide(tokens) {
  
// code
}

//#CLIENTSIDE
function onPlayerChats() {
  if (
player.chat.starts("/copy")) {
    
temp.tokens player.chat.tokenize();
    
triggerServer("gui"this.nametokens);
  }

You can then check for the command and find the player

PHP Code:
function onActionServerSide(tokens) {
  if (
tokens[0] == "/copy") {
    
temp.pl findPlayerByCommunityName(tokens[1]);
  }
}

//#CLIENTSIDE
function onPlayerChats() {
  if (
player.chat.starts("/copy")) {
    
temp.tokens player.chat.tokenize();
    
triggerServer("gui"this.nametokens);
  }

For an example of triggering back to clientside, see


Quote:
Originally Posted by cbk1994 View Post
Nope. You can trigger either way back and forth as much as you want. You can create an infinite loop if you want:

PHP Code:
function onActionServerSide(cmd) {
  if (
cmd == "ping") {
    
triggerClient("gui"this.name"ping");
  }
}

//#CLIENTSIDE
function onCreated() {
  
triggerServer("gui"this.name"ping"); // start the loop
}

function 
onActionClientSide(cmd) {
  if (
cmd == "ping") {
    
this.counter ++;
    
player.chat "Pings: " this.counter;
    
triggerServer("gui"this.name"ping");
  }

Though obviously you wouldn't want to do something like that in practical scripting

You can also trigger weapons of other players.

PHP Code:
function onActionServerSide(cmdtargetmsg) {
  if (
cmd == "tell") {
    
temp.pl findPlayerByCommunityName(target);
    
    if (
pl == null) {
      return 
player.chat "(player not found)";
    }
    
    
pl.triggerClient("gui"this.name"tell"player.communitynamemsg);
  }
}

//#CLIENTSIDE
function onPlayerChats() {
  if (
player.chat.starts("tell")) { // format is: tell account "message here"
    
temp.tokens player.chat.tokenize();
    
    
temp.acc tokens[1];
    
temp.msg tokens[2];
    
    
triggerServer("gui"this.name"tell"accmsg);
  }
}

function 
onActionClientSide(cmdsendermsg) {
  if (
cmd == "tell") {
    
player.chat sender ": " msg;
  }

To use this you would say: tell cbk1994 "Hi there ugly!"

That would trigger serverside, try to find a player with the community name 'cbk1994', and if found, trigger clientside on the same weapon for that player. Once it receives the trigger clientside, it would set my chat to 'Engine: Hi there ugly!'.

This is a bit of a silly example since you can set players' chat serverside, but it could be used, for example, if you have some kind of GUI window displaying the message.

Sorry for the long posts but if you're interested in learning they should clear it up pretty well.
__________________
Reply With Quote
  #6  
Old 01-02-2011, 12:20 AM
AlexanderK AlexanderK is offline
Registered User
AlexanderK's Avatar
Join Date: Mar 2006
Location: Germany
Posts: 79
AlexanderK is on a distinguished road
Send a message via MSN to AlexanderK
Thanks, your post helped me understand triggering between the two sides.

It looks like I have to rethink the whole thing, as triggerClient and triggerServer can't handle arrays... Wow this is frustrating.
Reply With Quote
  #7  
Old 01-02-2011, 12:25 AM
Crow Crow is offline
ǝɔɐɹq ʎןɹnɔ
Crow's Avatar
Join Date: Dec 2006
Location: Germany
Posts: 5,153
Crow has a reputation beyond reputeCrow has a reputation beyond reputeCrow has a reputation beyond reputeCrow has a reputation beyond reputeCrow has a reputation beyond reputeCrow has a reputation beyond reputeCrow has a reputation beyond reputeCrow has a reputation beyond reputeCrow has a reputation beyond reputeCrow has a reputation beyond reputeCrow has a reputation beyond repute
Quote:
Originally Posted by AlexanderK View Post
as triggerClient and triggerServer can't handle arrays
Wat.
Reply With Quote
  #8  
Old 01-02-2011, 12:38 AM
cbk1994 cbk1994 is offline
the fake one
cbk1994's Avatar
Join Date: Mar 2003
Location: San Francisco
Posts: 10,718
cbk1994 has a reputation beyond reputecbk1994 has a reputation beyond reputecbk1994 has a reputation beyond reputecbk1994 has a reputation beyond reputecbk1994 has a reputation beyond reputecbk1994 has a reputation beyond reputecbk1994 has a reputation beyond reputecbk1994 has a reputation beyond reputecbk1994 has a reputation beyond reputecbk1994 has a reputation beyond repute
Send a message via AIM to cbk1994
Quote:
Originally Posted by Crow View Post
Wat.
This. triggerServer and triggerClient definitely work with arrays.
__________________
Reply With Quote
  #9  
Old 01-02-2011, 12:51 AM
AlexanderK AlexanderK is offline
Registered User
AlexanderK's Avatar
Join Date: Mar 2006
Location: Germany
Posts: 79
AlexanderK is on a distinguished road
Send a message via MSN to AlexanderK
Quote:
Originally Posted by cbk1994 View Post
This. triggerServer and triggerClient definitely work with arrays.
It does? Well that's good to hear.

But I still don't see why this doesn't work:
NPC Code:
function onActionServerSide(param) {
if(param==null) {
temp.categories=player.getCategories();
triggerClient("gui", this.name, categories);
}
}
//#CLIENTSIDE
function onCreated() {
this.setshape(1,32,64);
this.chat="Touch me to find out how many categories you have";
}
function onPlayerTouchsMe()
{
triggerServer("gui", this.name,null);

}
function onActionClientSide(categories) {
this.chat="Categories: " @ categories.size() @ " first category: " @ categories[][];
}


Maybe it's just too late. Thanks for the help, I'm heading to bed now.
Reply With Quote
  #10  
Old 01-02-2011, 01:28 AM
WhiteDragon WhiteDragon is offline
Banned
Join Date: Feb 2007
Posts: 1,002
WhiteDragon is a splendid one to beholdWhiteDragon is a splendid one to beholdWhiteDragon is a splendid one to beholdWhiteDragon is a splendid one to beholdWhiteDragon is a splendid one to behold
If you call triggerserver or triggerclient with only one value, and that value is an array, it'll set params to that array rather than just the first variable. I think.
Reply With Quote
  #11  
Old 01-02-2011, 02:06 AM
cbk1994 cbk1994 is offline
the fake one
cbk1994's Avatar
Join Date: Mar 2003
Location: San Francisco
Posts: 10,718
cbk1994 has a reputation beyond reputecbk1994 has a reputation beyond reputecbk1994 has a reputation beyond reputecbk1994 has a reputation beyond reputecbk1994 has a reputation beyond reputecbk1994 has a reputation beyond reputecbk1994 has a reputation beyond reputecbk1994 has a reputation beyond reputecbk1994 has a reputation beyond reputecbk1994 has a reputation beyond repute
Send a message via AIM to cbk1994
The problem is that you can't trigger a NPC with this.name. You'd either have to use triggeraction with the NPC's x/y (not recommended) or create a weapon to handle it. My suggestion would be like:

PHP Code:
//#CLIENTSIDE

  
function onCreated() {

 
this.setshape(1,32,64);

  
this.chat="Touch me to find out how many categories you have";

 }

function 
onPlayerTouchsMe() {
  
// passing this npc as a parameter so it can store it so it knows
  // which npc's chat to update
  
(@ "-MyCategoryWeapon").showCategories(this);
}

function 
onPlayerTouchsMe()

 {

 
triggerServer("gui"this.name,null);



 } 
Script of weapon -MyCategoryWeapon, added to players on login
PHP Code:
function onActionServerSide(param) {

  if(
param=="getCategories") { // it's a good idea to always have a "command" parameter

  
temp.categories=player.getCategories();

  
triggerClient("gui"this.namecategories);

  }

 }

//#CLIENTSIDE
public function showCategories(npcToUpdate) {
  
this.npcToUpdate npcToUpdate;
  
triggerServer("gui"this.name"getCategories");
}

function 
onActionClientSide(categories) {

 
this.npcToUpdate.chat="Categories: " categories.size() @ " first category: " categories[][];


also, please use [PHP] and [/PHP] instead of [CODE].

Quote:
Originally Posted by WhiteDragon View Post
If you call triggerserver or triggerclient with only one value, and that value is an array, it'll set params to that array rather than just the first variable. I think.
I'm 99% certain it doesn't happen.
__________________
Reply With Quote
  #12  
Old 01-02-2011, 02:10 AM
WhiteDragon WhiteDragon is offline
Banned
Join Date: Feb 2007
Posts: 1,002
WhiteDragon is a splendid one to beholdWhiteDragon is a splendid one to beholdWhiteDragon is a splendid one to beholdWhiteDragon is a splendid one to beholdWhiteDragon is a splendid one to behold
Quote:
Originally Posted by cbk1994 View Post
I'm 99% certain it doesn't happen.
I've had it happen before, I'm just not sure what the exact conditions are for it to happen. It could be a v6-only thing.
Reply With Quote
  #13  
Old 01-06-2011, 04:36 PM
AlexanderK AlexanderK is offline
Registered User
AlexanderK's Avatar
Join Date: Mar 2006
Location: Germany
Posts: 79
AlexanderK is on a distinguished road
Send a message via MSN to AlexanderK
Thanks for the help again cbk1994. I managed to get most of my Inventory done, as it is a weapon and I can use triggerserver and triggerclient without problems.
However I still can't access my player. itemfunctions from normal NPCs . Even though I copied your suggestion and only changed a few minor things, I get this error:
Quote:
Script: Function -ItemServerFunctions.showCategories not found at line 10 in script of npcs[13] (in level tilestest.nw at pos (32, 18))
I have no idea what the problem is, as the player has this weapon...

Here is the script of the NPC.
PHP Code:
 //#Clientside
  
function onCreated() 
 {
 
this.setshape(1,32,64);

 }
function 
onPlayerChats() {
  
temp.tokens player.chat.tokenize();
  if (
tokens[0]=="/getcategories"
  (@
"-ItemServerFunctions").showCategories(this);


This is the script of the weapon -ItemServerFunctions
PHP Code:
function onActionServerSide() {

  if(
params[0]=="getCategories") {
    
temp.categories=player.getCategories();
    
triggerClient("gui"this.namecategories);
  }
  
  if(
params[0]=="addItem") {
    
player.addItem(params[1], params[2], params[3], params[4], params[5], params[6]);
  }
  
 }

//#CLIENTSIDE

public function showCategories(npcToUpdate) {
  
this.npcToUpdate npcToUpdate;
  
triggerServer("gui"this.name"getCategories");
}

public function 
addItem(category,itemname,equippable,droppable,usable,quantity) {
  
triggerServer("gui"this.name"addItem"categoryitemnameequippabledroppableusablequantity);
}

function 
onActionClientSide(categories) {
 
this.npcToUpdate.chat="Categories: " categories.size() @ " first category: " categories[0][0];

Man... All these interactions between different objects and sides is so complicated.
Reply With Quote
  #14  
Old 01-06-2011, 04:43 PM
fowlplay4 fowlplay4 is offline
team canada
fowlplay4's Avatar
Join Date: Jul 2004
Location: Canada
Posts: 5,200
fowlplay4 has a reputation beyond reputefowlplay4 has a reputation beyond reputefowlplay4 has a reputation beyond reputefowlplay4 has a reputation beyond reputefowlplay4 has a reputation beyond reputefowlplay4 has a reputation beyond reputefowlplay4 has a reputation beyond reputefowlplay4 has a reputation beyond reputefowlplay4 has a reputation beyond reputefowlplay4 has a reputation beyond reputefowlplay4 has a reputation beyond repute
In your first script you have a space into front of //#CLIENTSIDE which is causing the entire script to be interpreted on the server-side.

For the sake of the security of your server, please remove your addItem client-side function.

That's basically a free pass for hackers to add whatever item they want and your system won't have a problem with it.
__________________
Quote:
Reply With Quote
  #15  
Old 01-06-2011, 04:46 PM
Tigairius Tigairius is offline
The Cat
Tigairius's Avatar
Join Date: Jan 2007
Location: Missouri, USA
Posts: 4,240
Tigairius has a brilliant futureTigairius has a brilliant futureTigairius has a brilliant futureTigairius has a brilliant futureTigairius has a brilliant futureTigairius has a brilliant futureTigairius has a brilliant futureTigairius has a brilliant future
In your NPC, you need to capitalize //#CLIENTSIDE.
__________________


“Shoot for the moon. Even if you miss, you'll land among the stars.”
Reply With Quote
Reply


Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off

Forum Jump


All times are GMT +2. The time now is 11:18 AM.


Powered by vBulletin® Version 3.8.11
Copyright ©2000 - 2025, vBulletin Solutions Inc.
Copyright (C) 1998-2019 Toonslab All Rights Reserved.