Difference between revisions of "Tic Tac Toe/Summary"

From Second Life Wiki
Jump to navigation Jump to search
m (TicTacToeSummary moved to Tic Tac Toe/Summary: CamelCasingIsReallyReallyBad)
(wiki-fu)
 
Line 1: Line 1:
{{LSL Header}}
{{LSL Header}}
 
{{:Tic Tac Toe/navigation}}
== All Scripts on a Single Page ==


The object we are scripting is composed of 9 cubes with an X/O texture pre-set and a back pane prim as the root prim. The link order of the child prims is assumed to be in any sequential reading order (left to right, top to bottom or similar).
The object we are scripting is composed of 9 cubes with an X/O texture pre-set and a back pane prim as the root prim. The link order of the child prims is assumed to be in any sequential reading order (left to right, top to bottom or similar).


=== Root Prim ===
== Root Prim ==


The root prim is populated with the scripts below:
The root prim is populated with the scripts below:


==== RootNanny (processes upload requests onto the child prims and manages object name) ====
=== RootNanny (processes upload requests onto the child prims and manages object name) ===
<pre>
<lsl>
// Message constants
// Message constants
integer MSG_RESET = 0;
integer MSG_RESET = 0;
Line 108: Line 107:
     }
     }
}
}
</pre>
</lsl>


==== Controller (game logic) ====
=== Controller (game logic) ===
<pre>
<lsl>
// Message constants
// Message constants
integer MSG_RESET      = 0;
integer MSG_RESET      = 0;
Line 269: Line 268:
     }
     }
}
}
</pre>
</lsl>


=== Child Prims ===
== Child Prims ==


The child prims all have the same set of scripts:
The child prims all have the same set of scripts:


==== LinkNanny (answers queries from the RootNanny and manages the upload pin) ====
=== LinkNanny (answers queries from the RootNanny and manages the upload pin) ===
<pre>
<lsl>
// Message constants
// Message constants
integer MSG_RESET = 0;
integer MSG_RESET = 0;
Line 306: Line 305:
     }
     }
}
}
</pre>
</lsl>


==== TouchDisplay (handles clicks, displays game elements) ====
=== TouchDisplay (handles clicks, displays game elements) ===
<pre>
<lsl>
// Locations of various bits on the texture
// Locations of various bits on the texture
float e_pos_s = 0.75;
float e_pos_s = 0.75;
Line 407: Line 406:
     }
     }
}     
}     
</pre>
</lsl>
----
[[TicTacToeGameLogicTwo|prev]]

Latest revision as of 22:17, 2 January 2008

The object we are scripting is composed of 9 cubes with an X/O texture pre-set and a back pane prim as the root prim. The link order of the child prims is assumed to be in any sequential reading order (left to right, top to bottom or similar).

Root Prim

The root prim is populated with the scripts below:

RootNanny (processes upload requests onto the child prims and manages object name)

<lsl> // Message constants integer MSG_RESET = 0; integer MSG_LINK_QUERY = 10; integer MSG_LINK_REPLY = 11;

// Globals to propagate string version = "1.5"; integer pin = 321;


// State integer current_link_nr;

// Stuff to send out list remote_scripts = [ "TouchDisplay", "LinkNanny" ];

request_next_object_id(integer link_nr) {

   // Send message, transmitting pin, hoping to get back objectid
   llMessageLinked(link_nr, MSG_LINK_QUERY, (string)pin, NULL_KEY);
               
   // Set timer in case link isn't replying
   llSetTimerEvent(2); // 2 secs seems generous

}

default {

   state_entry()
   {
       string name = llGetObjectName();
       integer space = llSubStringIndex(name, " v");
       if (space < 0) llSetObjectName(name + " v" + version);
       else llSetObjectName(llDeleteSubString(name, space+2, -1) + version);
       llListen(1, "", llGetOwner(), "update");
   }
   listen(integer channel, string name, key id, string message)
   {
       state uploading;
   }

}

state uploading {

   state_entry()
   {
       current_link_nr = llGetNumberOfPrims();
       // Check if it's more than one
       if (1 < current_link_nr)
       {
           // avatars sitting on us get added at the end, so subtract...
           while (llGetAgentSize(llGetLinkKey(current_link_nr)))
               --current_link_nr;
           request_next_object_id(current_link_nr);
       }
   }
   
   link_message(integer from, integer msg_id, string str, key id)
   {
       if (from == current_link_nr && msg_id == MSG_LINK_REPLY)
       {
           llSetTimerEvent(0); // Cancel timeout
           integer i;
           for (i = 0; i < llGetListLength(remote_scripts); ++i)
           {
               string script = llList2String(remote_scripts, i);
               llSay(0, "Uploading '"+script+"' to link nr "+(string)current_link_nr);
               llRemoteLoadScriptPin(id, script, pin, TRUE, 0);
           }
           current_link_nr--;
           if (1 < current_link_nr)
           {
               request_next_object_id(current_link_nr);
           }
           else
           {
               llSay(0, "Done uploading remote scripts.");
               state default;
           }
       }
   }
   
   timer()
   {
       llSay(0, "Failed to receive reply from link nr "+(string)current_link_nr);
       current_link_nr--;
       if (1 < current_link_nr)
       {
           request_next_object_id(current_link_nr);
       }
       else
       {
           llSay(0, "Done uploading remote scripts.");
           state default;
       }
   }

} </lsl>

Controller (game logic)

<lsl> // Message constants integer MSG_RESET = 0; integer MSG_TOUCH = 1; integer MSG_SET_X = 2; integer MSG_SET_O = 3; integer MSG_IDLE = 4; integer MSG_IDLE_TOUCH = 5; integer MSG_WIN = 6;

// Game timeout integer GAME_TIMEOUT = 20;

// Game state key player_x; key player_o; string turn; string game;

string at(integer u, integer v) {

   integer p = u*3+v;
   return llGetSubString(game, p, p);

}

// return TRUE if game ends integer game_ends(string player, integer move) {

   game = llInsertString(llDeleteSubString(game, move, move), move, player);
   llSay(0, "game = "+game);
   // Check if this made three in a row
   integer u = move / 3;
   integer v = move % 3;
   integer i;
   integer c;
   
   // check horizontal
   c = 0;
   for (i = 0; i < 3; i++) if (at(i, v) == player) c++;
   if (c == 3)
   {
       for (i = 0; i < 3; i++) llMessageLinked(2 + 3*i + v, MSG_WIN, "", NULL_KEY);
       return TRUE;
   }
   
   // check vertical
   c = 0;
   for (i = 0; i < 3; i++) if (at(u, i) == player) c++;
   if (c == 3)
   {
       for (i = 0; i < 3; i++) llMessageLinked(2 + 3*u + i, MSG_WIN, "", NULL_KEY);
       return TRUE;
   }
   
   // check if we are on one diagonal
   c = 0;
   if (u == v) for (i = 0; i < 3; i++) if (at(i, i) == player) c++;
   if (c == 3)
   {
       for (i = 0; i < 3; i++) llMessageLinked(2 + 4*i, MSG_WIN, "", NULL_KEY);
       return TRUE;
   }
   
   // check if we are on the other diagonal
   c = 0;
   if (u + v == 2) for (i = 0; i < 3; i++) if (at(i, 2-i) == player) c++;
   if (c == 3)
   {
       for (i = 0; i < 3; i++) llMessageLinked(4 + 2*i, MSG_WIN, "", NULL_KEY);
       return TRUE;
   }
   
   // Check if there are any spaces left
   if (llSubStringIndex(game, "-") < 0) return TRUE;
   // Game goes on
   return FALSE;

}

default {

   state_entry()
   {
       player_x = NULL_KEY;
       player_o = NULL_KEY;
       game = "---------";
       turn = "x";
       llMessageLinked(LINK_ALL_CHILDREN, MSG_RESET, "", NULL_KEY);
       state playing;
   }

}

state playing {

   link_message(integer from, integer msg_id, string str, key id)
   {
       if (msg_id == MSG_TOUCH)
       {
           llSay(0, "touch from "+(string)from);
           if (turn == "x" && NULL_KEY == player_x)
           {
               llSetTimerEvent(0);
               llMessageLinked(from, MSG_SET_X, "", NULL_KEY);
               player_x = id;
               if (game_ends(turn, from-2)) state idle;
               turn = "o";
               llSetTimerEvent(GAME_TIMEOUT);
           }
           else if (turn == "o" && NULL_KEY == player_o)
           {
               llSetTimerEvent(0);
               llMessageLinked(from, MSG_SET_O, "", NULL_KEY);
               player_o = id;
               if (game_ends(turn, from-2)) state idle;
               turn = "x";
               llSetTimerEvent(GAME_TIMEOUT);
           }
           else if (turn == "x" && id == player_x)
           {
               llSetTimerEvent(0);
               llMessageLinked(from, MSG_SET_X, "", NULL_KEY);
               if (game_ends(turn, from-2)) state idle;
               turn = "o";
               llSetTimerEvent(GAME_TIMEOUT);
           }
           else if (turn == "o" && id == player_o)
           {
               llSetTimerEvent(0);
               llMessageLinked(from, MSG_SET_O, "", NULL_KEY);
               if (game_ends(turn, from-2)) state idle;
               turn = "x";
               llSetTimerEvent(GAME_TIMEOUT);
           }
       }
   }
   timer()
   {
       llSetTimerEvent(0);
       state idle;
   }

}

state idle {

   state_entry()
   {
       llSay(0, "state idle");
       llMessageLinked(LINK_ALL_CHILDREN, MSG_IDLE, "", NULL_KEY);
   }
   
   link_message(integer from, integer msg_id, string str, key id)
   {
       if (msg_id == MSG_IDLE_TOUCH) state default;
   }

} </lsl>

Child Prims

The child prims all have the same set of scripts:

LinkNanny (answers queries from the RootNanny and manages the upload pin)

<lsl> // Message constants integer MSG_RESET = 0; integer MSG_LINK_QUERY = 10; integer MSG_LINK_REPLY = 11;

default {

   state_entry()
   {
       // If we are in the the root prim...
       if (llGetLinkNumber() < 2)
       {
           // ... disable ourselves
           llSetScriptState(llGetScriptName(), FALSE);
           llSleep(2);
       }
   }
   
   link_message(integer from, integer msg_id, string str, key id)
   {
       if (msg_id == MSG_LINK_QUERY)
       {
           // Set pin given
           llSetRemoteScriptAccessPin((integer)str);
           // Tell caller who we are
           llMessageLinked(from, MSG_LINK_REPLY, "", llGetKey());
       }
   }

} </lsl>

TouchDisplay (handles clicks, displays game elements)

<lsl> // Locations of various bits on the texture float e_pos_s = 0.75; float e_pos_t = 0.75; float x_pos_s = 0.75; float x_pos_t = 0.25; float o_pos_s = 0.25; float o_pos_t = 0.25;

// Face on wjich the texture lives integer DISPLAY_FACE = 4; vector RED = <1,0,0>; vector WHITE = <1,1,1>;

// Message constants integer MSG_RESET = 0; integer MSG_TOUCH = 1; integer MSG_SET_X = 2; integer MSG_SET_O = 3; integer MSG_IDLE = 4; integer MSG_IDLE_TOUCH = 5; integer MSG_WIN = 6;

default {

   state_entry()
   {
       // If we are in the the root prim...
       if (llGetLinkNumber() < 2)
       {
           // ... disable ourselves
           llSetScriptState(llGetScriptName(), FALSE);
           llSleep(2);
       }
       
       // Reset color and texture
       llSetColor(WHITE, DISPLAY_FACE);
       llOffsetTexture(e_pos_s, e_pos_t, DISPLAY_FACE);
   }
   touch_start(integer touching_agents)
   {
       while (touching_agents--)
       {
           llMessageLinked(LINK_ROOT, MSG_TOUCH, "", llDetectedKey(touching_agents));
       }   
   }
   
   link_message(integer from, integer msg_id, string str, key id)
   {
       if (msg_id == MSG_SET_X) state x;
       if (msg_id == MSG_SET_O) state o;
       if (msg_id == MSG_IDLE) state idle;
   }

}

state x {

   state_entry()
   {
       llOffsetTexture(x_pos_s, x_pos_t, DISPLAY_FACE);
   }
   link_message(integer from, integer msg_id, string str, key id)
   {
       if (msg_id == MSG_RESET) state default;
       if (msg_id == MSG_IDLE) state idle;
       if (msg_id == MSG_WIN) llSetColor(RED, DISPLAY_FACE);
   }

}

state o {

   state_entry()
   {
       llOffsetTexture(o_pos_s, o_pos_t, DISPLAY_FACE);
   }
   link_message(integer from, integer msg_id, string str, key id)
   {
       if (msg_id == MSG_RESET) state default;
       if (msg_id == MSG_IDLE) state idle;
       if (msg_id == MSG_WIN) llSetColor(RED, DISPLAY_FACE);
   }

}

state idle {

   link_message(integer from, integer msg_id, string str, key id)
   {
       if (msg_id == MSG_RESET) state default;
   }
   touch_start(integer touching_agents)
   {
       llMessageLinked(LINK_ROOT, MSG_IDLE_TOUCH, "", NULL_KEY);
   }

} </lsl>