Showing posts with label llSay. Show all posts
Showing posts with label llSay. Show all posts

Monday, August 25, 2008

Second Life Physics Scripting #28 - disconnecting users

I arrived at the game to find that it would not let me start because it thought someone else was still playing.

This is the code that wasn't allowing me to join.


touch_start(integer total_number)
{
if (avatar_attached)
{
llSay(0, "Currently allows only one player at a time. Sorry.");
return;
}

But the real problem was in the avatar_attached flag not being reset. The user must have logged out without hitting the release keys button so I never go the disconnect event. There doesn't seem to be anyway to drop those connections so I need to at least pay attention to their distance from the table.

This is the new timer code.

timer()
{
....

// see if we still have control
if (avatar_attached)
{
if( !(llGetPermissions() & PERMISSION_TAKE_CONTROLS) )
{
auto_tick_count = 0;
avatar_attached = FALSE;
}
else
{
// check the distance to the avatar...
key curkey = llGetPermissionsKey();

list temp;
vector pos;
vector pos2;

temp = llGetObjectDetails(curkey,[OBJECT_POS]);
pos = llList2Vector(temp,0);

pos2 = llGetRootPosition();

float dist = llVecDist(pos,pos2);
llOwnerSay("dist = "+(string)dist);
if (dist>15)
{
llSay(0,"Player too far away - resetting");
auto_tick_count = 0;
avatar_attached = FALSE;
llRequestPermissions(avatar_key, 0);
avatar_key = NULL_KEY;
}
}
}
}

I get the key of the avatar that is currently attached. Then I check that avatar's distance. If they are too far away, I reset the avatar attached key. There was still one more problem if they walked back into the area then they could still send control events so I added some extra code to runtime permissions to save the last player that attached.


run_time_permissions(integer perm)
{
// permissions dialog answered
if (perm & PERMISSION_TAKE_CONTROLS)
{
// we got a yes
// take up and down controls
llTakeControls(CONTROL_ROT_LEFT | CONTROL_ROT_RIGHT | CONTROL_UP | CONTROL_DOWN, TRUE, FALSE);
// remove any balls on the table
llSay(1296,"byebye");
in_play = FALSE;

avatar_attached = TRUE;
avatar_key = llGetPermissionsKey();
RestartGame();
}
}


And then to the control code to double check the current key with the key sending the control event.


control(key id, integer held, integer change)
{
if (id!=avatar_key)
{
list temp = llGetObjectDetails(id,[OBJECT_NAME]);
string nm = llList2String(temp,0);

llSay(0,nm+", you have been disconected, press the Release Keys button and touch the pinball machine again.");
return;
}

I wanted to send them the message directly and probably can with an IM, but for now it was just easier to send it with their name attached to identify that the message was to them.

Wednesday, August 20, 2008

Second Life Physics Scripting - Pinball #25 - A Bit Of Art

I played around with the art a little today, just using the standard sunset images that come with every second life inventory. I'm planning on making some images of a bunch of people and trying to use those.

I added some code to see if anyone actually plays the game. This just saves each name to a list and I listen for a specific chat and print out the list if the machine hears me.


list player_list;

integer isNameOnList( string name )
{
integer len = llGetListLength( player_list );
integer i;
for( i = 0; i < len; i++ )
{
if( llList2String(player_list, i) == name )
{
return TRUE;
}
}
return FALSE;
}


state_entry()
{
...
listen_handle = llListen( 0, "", llGetOwner(), "" );
...
}
touch_start(integer total_number)
{
...
string detected_name = llDetectedName( 0 );
//if( isNameOnList( detected_name ) == FALSE )
if( detected_name != "Wood Wheels" )
{
player_list += detected_name;
}
}
listen(integer channel, string name, key id, string message)
{
...
else if ((channel==0) && (llToLower(message)=="players"))
{
llSay( 0, "Player List:" );
integer len = llGetListLength( player_list );
integer i;
for( i = 0; i < len; i++ )
{
llSay( 0, llList2String(player_list, i) );
}
llSay( 0, "Total = " + (string)len );

llSay(0," High Score - "+highscore_name+" - "+(string) highscore);
}
}

It has been a few days since that time and no one has played it. I did attract some sort of interest tough because the previously empty land above me has added an advertising post. I wouldn't normally mind, but since it had some sort of porn ad I placed a brick wall in front of it.



I need to do some work on the art and layout and then add some more game play elements, like scoring better than 1 point per bumper bounce.

Wednesday, July 30, 2008

Second Life Physics Scripting - Pinball #23 - llRez and llDie

The next feature is to remove the ball when it hits the back wall and then to have it respawn when the user presses the page up key.

The first problem is that the ball has to remove itself. There doesn't seem to be a way to have a script remove another object.

I first set out to have the ball remove itself when it had a collision with the back wall. The problem with this is that the back wall is linked and the collision name had "pinball 1.4" which may change over time and that this collision only occured once when the ball was first placed on the table since it is all one linked set.

The next solution is to send a message to the ball when the back wall is hit and I did this with the chat system llSay.


if (llDetectedName(0) == "ball")
{
...
//llPushObject(llDetectedKey(0), pos3, <0,0,0>, FALSE);

llSay(1296,"byebye");

}

This was as simple as removing the push and adding the llSay. The next step is to have the ball listen for the message.

integer listen_handle;

default
{
state_entry()
{
listen_handle = llListen( 1296, "backwall", NULL_KEY, "" );
}
listen(integer channel, string name, key id, string message)
{

//llOwnerSay("ball listen, heard = "+name);
if ((channel==1296) && (llToLower(message) == "balldied"))
{
//llOwnerSay("Ball died!");
llDie();
}
}

}

The ball is listening for the object backwall to say "byebye" on channel 1296. At first I thought this would be too slow, but it seems very quick and the ball goes away before bouncing back onto the table.

Make sure you keep a copy of the ball in your inventory because when it dies you don't want to have to recreate the scripts over and over.

The next step is the spawning of the ball (llRez) when the user presses the page up key. I did this in the PayAndKeyboard script in root table object. This is the same script that handles the key presses to move the puck flipper.


RezBall()
{
if (!in_play)
{
in_play = TRUE;

// find the size of the this table
vector sz = llList2Vector(llGetPrimitiveParams([PRIM_SIZE]),0);

vector pos = llGetPos();
//llOwnerSay("pos = "+(string)pos);
vector up = llVecNorm(pos * llGetLocalRot());
up = up * ((sz.z/2) + 0.21); // add the size of the ball
//llOwnerSay("up = "+(string)up);

pos = pos + up;
//llOwnerSay("rez pos = "+(string) pos);

llRezObject("ball",pos,<0,0,0>,ZERO_ROTATION,0);
}
}

I wrote a separate function for the rez ball. This still has problems as I think it rezes the ball too low on the table, but it has a neat effect in that the ball sort of oozes out of the table. It needs looking into at some point.

Next is the event to rez the ball.

control(key id, integer held, integer change)
{
... puck flipper code

// page up key
if ((held&CONTROL_UP) && (change&CONTROL_UP))
{
if (!in_play)
{
llSay(0," here we go!!!");
}
RezBall();
}
}


Then we have to have a way to reset the in_play flag so the user can press the "page up" key again and have the ball rez. This is as simple as adding the listen method the same as we used for the ball. Both the ball and this PayAndKeyboard script will both hear the same message from the backwall.

state_entry()
{

listen_handle = llListen( 1296, "backwall", NULL_KEY, "" );
llSetTimerEvent(30);

... other initialization code
}

listen(integer channel, string name, key id, string message)
{
if ((channel==1296) && (llToLower(message) == "balldied"))
{
llSay(0,"Oops, drain. Press 'Page Up' to start another ball.");
in_play = FALSE;
llSetTimerEvent(30);
}
}

As you can see I also added some timer events. This is so the table is actually doing something when people first walk up to it. A teaser to get people interested. 30 seconds after every drain, then timer goes off. If the ball isn't already in play (because someone pushed page up), then a new ball is spawned.

timer()
{
if (!in_play)
{
llSay(0,"Autoplay starting");
RezBall();
}
llSetTimerEvent(0);
}