Adding Groups to the Planet Oit

Back to Table of Contents

This document describes a code design that would allow the creation of groups on the Planet. It is not complete and is under complete review. If you see something potentially missing, send an e-mail to Otto, and I'll get right on it.

For a list of basic requirements, see the requirements document.

Note to the reader: This document is color coded for assumed readability:

This is a property definition

This is a verb definition

This is a directive sent to the client by the server => And this is who it is sent to

This is a history entry stored on the server

(*) indicates a design question being posed, may not be answered yet

(**) Is the answer to the question immediately before it

(I) is implemented on Oit


Hooks into current game (Need to be added to any new MOO)

list $g.game_player.groups - list of object numbers indicating what groups an explorer belongs to

list $g.game_player.group_member_permissions - list of 1 and 0's indicating what permissions a group member has by default

list $g.game_player.group_leader_permissions - list of 1 and 0's indicating what permissions a group leader has by default

Present permissions are as follows: {CanFollow, CanInvite, CanRemove, CanRename, CanChangeGoal, CanSetLeader, CanDisband}

$g.game_player:confunc() - Changes to this function to call $g.group:confunc()

$g.game_player:disfunc() - Changes to this function to call $g.group:disfunc()

$g.game_exit:invoke - Changes to this function to call $g.group:invoke_follow

$g.game_player:group any none none rxd - Verb added to access group functions by player
Described below

$g properties:

  1. $g.group - object number of group object described below (I)
  2. $g.group_room - room where group objects are located (I)

New object

$g.group - Parent object of all groups, new groups are children of this group.

The group object number is sent to graphical clients in the case that people can be in multiple groups at one time.

Verbs:

(*) Do we want these to return ints to allow for error messages? Or do the verbs themselves emit errors? (May want to do both)

void send_goal_orderings(OBJ explorer)

Call: $g.group:send_goal_orderings(OBJ explorer) (I)
Called By: $g.game_player:group
Return Value: None
Args: explorer - display the goals this player can have
Function: Sends the potential modules that a group can do. Function is called by the graphical client to get modules for addition into a list. Now calls $g.group_modules which performs all group goal tasks.
Client Message: Determined by objects in $g.group_modules
History Entry: None
Notes:

OBJ create(OBJ leader) (I)

Call: $g.group:create(OBJ leader)
Called By: $g.game_player:group, $g.computer_selected_group_im_goal:start_goal (#1742 on Oit)
Return Value: Object number of the group that was created
Args: OBJ leader - player that will become the leader
Function: Makes child of $g.group with leader as the only member. Sets leader as the new leader. Move the new group object to $g.group_room.
Client Message: Sends this:status(explorer) message
History Entry: {timestamp, "created group", leader, {}, group_name}
Notes: (*) Makes them a leader? (**) Yes
(*) How would a professor create a group? (**) Create group with player set different from current player to create group like that. (**) Don't know if this is necessary. If the professor wants to create a group, ask the students to do so. Or create one themselves and add people
(*) How does it set a group goal? (**) Players select the first goal they wish (**) Teachers should be able to set initial player goals if they want (They can, using assign_goal)

OBJ create_group_object(OBJ leader)

Call: $g.group:create_group_object(OBJ leader)
Called By: this.group:create
Return Value: Object number of the created group object
Args: OBJ leader - player that created the group, used so that group objects can be organized into classes
Function: Internal function that actually creates a new group object, and, if necessary, its parent. (Groups are sorted by class)
Client Message: None
History Entry: None
Notes:

void invite(OBJ explorer)

Call: $g.group:invite(OBJ explorer)
Called By: $g.game_player:group
Return Value: None
Args: OBJ explorer - player to invite
Function: Send an invitation message to explorer if they haven't recently declined
Client Message: #GROUP|group_obj_num|declining join|explorer.name|seconds left before can invite again => leader if invited to recently
#GROUP|group_obj_num|request join|leader.name|group.name => explorer otherwise
History Entry: None
Notes:

int are_declining_for(OBJ explorer)

Call: $g.group:are_declining_for(OBJ explorer)
Called By: this.group:invite
Return Value: Number of seconds before this person can be invited to a group again (because they have declined before) (Ex: You can only invite a person once every 30 seconds (change duration in $g.group:decline_join))
Args: OBJ explorer - player to check
Function: Internal function that returns how long before someone can ask explorer to join this group.
Client Message: None (performed in this.group:invite)
History Entry: None
Notes:

int decline_join(OBJ explorer)

Call: $g.group:decline_join(OBJ explorer)
Called By: $g.game_player:group
Return Value: None
Args: OBJ explorer - player that is declining
Function: Sends a message to the leader, saying explorer has declined to join and add them to a list so they aren't bothered for a bit
Client Message: #GROUP|group_obj_num|declining join|explorer.name|30 => leader
History Entry: None
Notes:

void invoke_follow(OBJ mover, OBJ invoked_exit)

Call: $g.group:invoke_follow(OBJ mover, OBJ invoked_exit)
Called By: $g.game_exit:invoke
Return Value: None
Args: OBJ mover - The player who's moving
OBJ invoked_exit - The exit their moving through
Function: Function that is called when someone goes through an exit. It moves people who should be following them through the exit as well.
Client Message: None
History Entry: None
Notes:

void is_following()

Call: $g.group:is_following()
Called By: $g.group:invoke_follow
Return Value: list of people who are following the leader in this group
Args: None
Function: Returns whoever is following, so they can be moved as well
Client Message: None
History Entry: None
Notes:

void change_permissions(OBJ explorer, list permissions)

Call: $g.group:change_permissions(OBJ explorer, list permissions)
Called By: this.group:set_leader
Return Value: None
Args: OBJ explorer - who's permissions to change
list permissions - what to change their permissions to
Function: Internal function that changes the permissions of a group member (usually used to transfer leadership permissions)
Client Message: None (performed in this.group:set_leader)
History Entry: None
Notes:

STR member_permissions(OBJ explorer)

Call: $g.group:member_permissions(OBJ explorer)
Called By: this.group:status
Return Value: Comma delimited string of explorer's permissions in this group
Args: OBJ explorer - whose permissions to retrieve
Function: Converts the permission list from member_info into a string
Client Message: None
History Entry: None
Notes:

void choose_module(STR goal_name)

Call: $g.group:choose_module(STR goal_name)
Called By: $g.game_player:group
Return Value: None
Args: STR goal_name - Name of the goal the user has selected in the client
Function: Changes the STR goal_name sent by the client into an OBJ module, then calls assign_goal to set the group goal
Client Message: None
History Entry: None
Notes:

void assign_goal(OBJ module)

Call: $g.group:assign_goal(OBJ module)
Called By: group_goal:complete_goal, group:choose_module
Return Value: None
Args: OBJ module - module the group is working on, assigns the group the next goal in the module they can do
Function: Sets the group goal to the next available goal in module
Client Message: If group finished module == #GROUP|group_obj_num|finished goal
Calls group_goal:send_goal_directive to send the goal information to everyone in the group
History Entry: {timestamp, "set goal", leader, {group_members}, new_goal, activity}
Notes:

void confunc(OBJ explorer)

Call: $g.group:confunc(OBJ explorer)
Called By: $g.game_player:confunc
Return Value: None
Args: OBJ explorer - player that is connecting
Function: Performs initialization of the client for connecting group members. Send initial status message, group goal connection information, a message to group members that explorer has connected, a message if they have unread bulletin board messages and send group options
Client Message: #GROUP|group_obj_num|say|explorer.name has connected. => group:members()
#GROUP|group_obj_num|say|unread notes message => explorer that has unread notes
#OPTION|can create groups => explorer that can create groups
History Entry: None
Notes:

void disfunc(OBJ explorer)

Call: $g.group:disfunc(OBJ explorer)
Called By: $g.game_player:disfunc
Return Value: None
Args: OBJ explorer - player that is leaving
Function: Send a message to the group that a player is leaving, and perform any goal functions that should be done on disconnection
Client Message: #GROUP|group obj num|say|explorer.name has left => all other group members
History Entry: None
Notes:

void add_member(OBJ explorer) (I)

Call: $g.group:add_member(OBJ explorer)
Called By: $g.game_player:group
Return Value: 0 if add was successful
-1 if explorer is not a player
Args: OBJ explorer - player that will be added
Function: Adds a person to the members list.
Client Message: #GROUP|group obj num|add|member name|role|following|can_remove|can_set_leader => $g.group:members() Note: can_remove and can_set_leader is either 1 or 0 indicating whether the person reciving the directive can remove the player or set him/her as the leader
History Entry: {timestamp, "added member", leader, {list of members *before* adding the new member}, member_to_add}
Notes:

void remove_member(OBJ explorer)

Call: group:remove_member(OBJ explorer)
Called By: $g.game_player:group
Return Value: None
Args: OBJ explorer - player that will be removed
Function: Remove a person from the members list. Calls disband if this is the last person in the group
Client Message: #GROUP|group obj num|remove|member name => All group members
History Entry: {timestamp, "removed member", leader, {list of members *before* removing the member}, member_to_remove}
Notes:

int follow(OBJ explorer) (I)

Call: group:follow(OBJ explorer)
Called By: $g.game_player:group
Return Value: 0 if successful
-1 if explorer is not a player
-2 if explorer is not in the group
Args: OBJ explorer - player that is changing their follow status
Function: Changes explorer's follow status
Client Message: #GROUP|group obj num|toggle follow|name => All group members
History Entry: {timestamp, "started following", explorer, group:members(), explorer} if player starts following
{timestamp, "stopped following", explorer, group:members(), explorer} if player stops following
Notes:

void set_name(STR name) (I)

Call: group:set_name(STR name)
Called By: $g.game_player:group
Return Value: None
Args: STR name - name to change the group name to
Function: Set a group's name to name
Client Message: #GROUP|group obj num|set name|name => All group members
History Entry: {timestamp, "set name to", leader, {members in group}, "name"}
Notes:

void say(OBJ explorer, STR group_msg) (I)

Call: group:say(OBJ explorer, STR group_msg)
Called By: $g.game_player:group
Return Value: None
Args: OBJ explorer - player that is actually saying group_msg
STR group_msg - message that will be sent to all players in group that are online
Function: Sends group_msg to all group members that are online
Client Message: #GROUP|group_obj_num|say|explorer.name : group_msg => All group members but explorer - If someone is online to hear explorer
#GROUP|group_obj_num|say|No one is connected message => explorer - If explorer is only group member that is online
History Entry: {timestamp, "said", explorer, {members in group (and online to receive the message) at the time}, "group_msg"}
Notes:


void status(OBJ explorer)

Call: group:status(OBJ explorer)
Called By: $g.group:confunc, $g.group:add_member, $g.group:create
Return Value: None
Args: OBJ explorer - player to send the status message to
Function: Returns group status
Client Message: #GROUP|group obj num|status| group.name|current goal name|current goal description|current goal activity|current group bulletin board|group permissions for explorer|number of players in the group|player 1 name|player 1 role|player 1 score|if player 1 is following|player 2 name|player 2 role|player 2 score|if player 2 is following => explorer
History Entry: None
Notes:

void disband()

Call: group:disband()
Called By: $g.game_player:group, group:remove_member
Return Value: None
Args: None
Function: Takes everyone out of the group.
Client Message: #GROUP|group obj num|remove|member name => all group members about each member removed (Number of messages == members * members)
History Entry: {timestamp, "disbanded group", leader, {members in group at time}, ""}
Notes:

void get_activity()

Call: group:get_activity()
Called By: Various - check $g:verb_grep
Return Value: None
Args: None
Function: Accessor function to retrieve the current group activity
Client Message: None
History Entry: None
Notes:

list members() (I)

Call: this:members()
Called By: All group functions
Return Value: List of object numbers of all players in the group
Args: None
Function: Returns a list of what members are in the group from the super-list member_info
Client Message: None
History Entry: None
Notes:


list search(OBJ explorer, int online, int in_class, int in_room, int same_goal, int not_in_group ) (I)

Call: group:search(OBJ explorer, int online, int in_class, int in_room, int same_goal, int not_in_group)
Called By: $g.game_player:group
Return Value: List of player names that match the given search criteria
Args: explorer = player that is doing the searching
Note: For all int arguments, -1 means that particular search term doesn't matter
int online = 1 - search for players that are online, 0 - search for players that are offline
int in_class = 1 - search for players in explorer's class, 0 - search for players that are not in explorer's class
int in_room = 1 - search for players in explorer's room, 0 - search for players not in explorer's room
int same_goal = 1 - search for players with the same goal as explorer, 0 - search for players without the same goal as explrer
int not_in_group = 1 - search for players not in a group, 0 - search for players in a group
Function: Search through game players to determine if they match a certain set of option criteria specified by the explorer, return a list of player names that match those criteria
Client Message: None
History Entry: None
Notes:


list search_by_name(STR player_to_search_for) (I)

Call: group:search_by_name(STR player_to_search_for)
Called By: $g.game_player:group
Return Value: List of player names that match player_to_search_by
Args: player_to_search_by - String to search for
Function: Searches for a player by name
Client Message: None
History Entry: None
Notes:


void send_directive_to_group(STR directive, list players_to_ignore) (I)

Call: group:send_directive_to_group(STR directive, list players_to_ignore)
Called By: Various
Return Value: None
Args: directive - directive to send
players_to_ignore - player to not send the directive to
Function: Sends a directive to group members
Client Message: directive => group:members() - players_to_ignore
History Entry: None
Notes:


void set_leader(OBJ leader) (I)

Call: group:set_leader(OBJ leader)
Called By: this:remove_member and $g.game_player:group
Return Value: 0 - successful
-1 - leader is not a player
-2 - leader is not in the group
Args: leader = player that will become the new leader
Function: Sets the leader of the group
Client Message: None (Calls this:status to display new leader)
History Entry: {timestamp, "set leader to", old leader obj num, {members in group}, leader obj num}
Notes: (*) This may be a security hazard. A simple say in a text window will allow a player to set him or herself as the leader of the group. (say #GROUP|group obj number|new leader|my name) or does the # need to be the first letter? notify() is a programmer only verb, if that is that case, and not a security hazard.


void read_note(OBJ note_reader, int note_number)

Call: player.group_member.group[n]:read_note()
Called By: $g.game_player:group
Return Value: None
Args: note_reader - player reading the note
note_number - index number of the note to read
Function: Given a note index number, give the text of the note to note_reader
Client Message: #GROUP|group obj num|read note|(int note number)|(string note text)
History Entry: None (*)
Notes:


void write_note(OBJ note_writer, STR note_subject, STR note_text)

Call: player.group_member.group[n]:write_note()
Called By: $g.game_player:group
Return Value: None
Args: note_writer = person that wrote the note
note_subject = subject of the note to add
note_text = text of the note to add
Function: Add note to list notes, send directive to all connected players that notes have been updated
Client Message: #GROUP|group obj num|new note|(int note number)|(string player string)|(string note text)
History Entry: Into list notes - {timestamp, note_writer, note_subject, note_text}
Notes:


void display_note_headers(OBJ explorer)

Call: player.group_member.group[n]:display_note_headers()
Called By: $g.game_player:group
Return Value: None
Args: explorer - player to send the note headers to
Function: Output all note headers (Ex: For text players, do this when asked, for graphical, do this on connect
Client Message: #GROUP|group obj num|new note|(int note number)|(string time_string)|(string player string)|(string note subject) => explorer
History Entry: None (*)
Notes:

Properties:

list history (I) - List of tuples { timestamp, action, group member performing action, {members in group}, result of action }

str name (I) - String containing the group's name

list module_search_order (I) - Ordering of group goals -- Not presently used

OBJ goal (I) - current goal of the group

OBJ leader (I) - current leader of the group

list member_info (I) - current members information of the group Presently a list of 3-tuples defined as {member_object_number, member_is_following, member_permissions} (*) This list could contain a variety of information about individuals in a group, including role, score, and permissions

int search_limit - Maximum number of results to return from the search() function shown above

OBJ bulletin_board - bulletin board associated with this group (used to store offline messages)

list declined_join - List of 2-tuples of players who have declined to join. Form: {player_obj_num, time_they_declined}

int uses_bulletin_boards - indicates whether this class actually uses bulletin boards or not (may be useful in future experiments)

OBJ activity - Activity that the group is presently doing. Right now it is used to store the server-side information about a map the group is drawing on

New Verb

Both client and text players can call these verbs to activate their functionality

(*) Must be able to pick which group you wish to change

$g.game_player:group any none none rxd

create - Call $g.group:create_group()

add (OBJ player) - Call player.group_member.group:add_member(player)

remove (OBJ player) - Call player.group_member.group:remove_member(player)

name (STR name) - Call player.group_member.group:set_name(name)

follow - Call player.group_member:toggle_follow()

say (STR group_msg) - Call player.group_member.group:group_say(group_msg)

status - Call player.group_member.group:group_status()

disband - Call player.group_member.group:disband()

leader (OBJ new_leader) - Call player.group_member.group:set_leader(new_leader)

note read (int note_number) - Call player.group_member:group:read_note(note_number)

note write(STR note_subject, STR note_text) - Call player.group_member:group:write_note(note_subject, note_text)

note show() - Call player.group_member:group:display_note_headers()

More Notes

(*) Still needs some work on the group creation process. How is a group assigned a goal?

(*) Group goals must have minimum number of group members, maximum number of group members, number and role of each group member, name of goal, ordering of goals into modules... (Other?) (**) Added information for number of group members needed to group_status and set_goal (*) Rather than having it in group_status, could poll the goal for this information?

(*) Is group information stored over logins? (**) Yes. If you want to leave a group, you must manual leave it, or have the group disbanded.

(*) Can you be in more than one group? (group_member.group needs to be a list, rather than a single object number, also need to be able to select what group you are talking about in $g.group verbs)

(*) Do we need a group module object to remain separate from individual player goals? Are these necessarily mutually exclusive? (Ex: Can an individual goal be a group goal?) (**) I think yes, if you want an individual goal to be a member of a particular group using a particular goal/role combination, just make is_completed check a person's group_member role history

(*) Can advertise that a player is looking for a group. Tutor can joing players who are physically distant.

(*) Needs to be exportable to other MOOs (**) See hooks above for what needs to be modified in MOOs this gets ported to

(*) How are team and individual goals different?

(*) Are goals chosen by player, assigned by program, or selected by professor?

(*) Do we want leader paradigm? A potential option is for any number or none to be leader (if professor is leader)

(*) Professor can create mandatory groups? (either manual selection or random selection)

(*) Split points evenly? Set by leader? Set by programmer? Professor? Embedded in goal?

(*) What goals can we even have?

(*) Should we separate the note interface from the group interface?

Role Notes

I think roles should be objects. Each role would have a list of actions that that particular role would gain points for, if the person does something in that list of actions, they get a certain number of points for being in the group. One could make roles be children of goals. (Goals that are part of the module are enumerated in module_search_order. A new property called roles would need to be added to group modules) We will also eventually need a tool that will allow a person to set up how they want groups and goals to be set up and created for a particular class.