/*
* Playground+ - robot_plists.c
* File to set up/handle/process the robots by Slaine
* --------------------------------------------------------------------------
*
* Permission has been granted to use this code within PG+
*/
#define ROB_VERS "1.2"
robot *robot_start = NULL;
void init_robots(void)
{
/* ok, lets set up a structure for all this crap :/ */
/* stored in player.h by the way */
char *oldstack, *scan, *scan2;
char nametoget[MAX_NAME];
char tmpstring[10];
file robots;
robot *current_robot = NULL;
robot *new_robot;
move *current_move;
move *new_move;
saved_player *sp;
log("boot", "Initialising robots");
oldstack = stack;
memset(nametoget, 0, MAX_NAME);
memset(tmpstring, 0, 10);
/* ok, lets try to read the robots file *fear* */
robots = load_file("files/robots");
if (!robots.where)
{
log("error", "Failed to load robots file.");
stack = oldstack;
return;
}
/* ok, in theory we have the robots file now, so lets try to read them in */
/* ah, need to set up a global robots pointer i guess */
robot_start = 0;
/* now we look at the file, a # is for a comment line */
/* format is:
name (lower case)
speed of operations
flags
# bit
actions
# bit */
scan = robots.where;
while (*scan)
{
/* get to the first name */
while (scan && *scan && !isalpha(*scan))
scan++;
if (scan && *scan)
{ /* ie we found a name i hope */
/* this is the bit that reads the records as it were in */
scan2 = nametoget;
while (isalpha(*scan))
*scan2++ = *scan++;
*scan2 = 0;
scan++; /* take it past the newline */
/* got the name, so now go find it */
sp = find_saved_player(nametoget);
if (sp)
{
/* we found one! */
new_robot = MALLOC(sizeof(robot));
if (!robot_start || robot_start == NULL)
{
robot_start = new_robot;
current_robot = new_robot;
}
else
{
current_robot->next = new_robot;
current_robot = new_robot;
}
current_robot->next = 0;
current_robot->actual_player = 0;
current_robot->moves_top = 0;
current_robot->max_moves = 0;
strcpy(current_robot->lower_name, nametoget);
/* we -should- be on the speed of ops bit now */
scan2 = tmpstring;
while (isdigit(*scan))
*scan2++ = *scan++;
*scan2 = 0;
scan++;
current_robot->speed = atoi(tmpstring);
current_robot->counter = 0;
/* get the flags */
scan2 = tmpstring;
while (isdigit(*scan))
*scan2++ = *scan++;
*scan2 = 0;
scan++; /* take it to the comment seperator */
scan += 2; /* take it to the first comment */
current_robot->flags = atoi(tmpstring);
/* fix stupid flags */
if (current_robot->flags & LOCAL_WANDER)
{
current_robot->flags &= ~WANDER;
current_robot->flags &= ~FIXED;
}
else if (current_robot->flags & WANDER)
{
current_robot->flags &= ~LOCAL_WANDER;
current_robot->flags &= ~FIXED;
}
else
{
current_robot->flags &= ~WANDER;
current_robot->flags &= ~LOCAL_WANDER;
current_robot->flags |= FIXED;
}
/* we are on first char of first action */
if (*scan && *scan != '#')
{
current_robot->moves_top = MALLOC(sizeof(move));
current_robot->moves_top->move_string[0] = 0;
current_robot->moves_top->next = 0;
current_move = current_robot->moves_top;
while (*scan && *scan != '#')
{
current_robot->max_moves++;
/* get the action */
scan2 = current_move->move_string;
while (*scan != '\n')
*scan2++ = *scan++;
scan++;
*scan2 = 0; /* terminator */
/* check to see if there is a next action */
if (*scan != '#')
{ /* malloc another one */
new_move = MALLOC(sizeof(move));
current_move->next = new_move;
new_move->move_string[0] = 0;
new_move->next = 0;
current_move = new_move;
}
}
}
else
{
current_robot->moves_top = 0;
}
}
else
{
sprintf(stack, "Failed to find save player for robot: %s", nametoget);
stack = end_string(stack);
log("robot", oldstack);
stack = oldstack;
/* skip actions for the robot */
while (*scan && *scan != '#')
scan++;
scan++;
while (*scan && *scan != '#')
scan++;
}
}
}
if (robots.where)
FREE(robots.where);
stack = oldstack;
}
/* list all the robot sections */
void list_robots(player * p, char *str)
{
char *oldstack;
robot *scan;
move *movescan;
int count = 0;
oldstack = stack;
if (robot_start == NULL)
{
tell_player(p, " There are no robots.\n");
return;
}
pstack_mid("Robot Information");
for (scan = robot_start; scan; scan = scan->next)
{
count++;
if (count > 1)
{
sprintf(stack, LINE "\n\n");
stack = strchr(stack, 0);
}
if (scan->flags & STORED)
sprintf(stack, "Name: %s (STORED)\n", scan->lower_name);
else
sprintf(stack, "Name: %s\n", scan->lower_name);
stack = strchr(stack, 0);
/* action times */
sprintf(stack, "Action every %d seconds, counter at %d\n", scan->speed, scan->counter);
stack = strchr(stack, 0);
/* flags */
if (scan->flags)
{
strcpy(stack, "Robot is ");
stack = strchr(stack, 0);
if (scan->flags & WANDER)
{
strcpy(stack, "fully wandering, ");
stack = strchr(stack, 0);
}
else if (scan->flags & LOCAL_WANDER)
{
strcpy(stack, "restricted to local rooms, ");
stack = strchr(stack, 0);
}
if (scan->flags & INTELLIGENT)
{
strcpy(stack, "artificially intelligent, ");
stack = strchr(stack, 0);
}
if (scan->flags & STORED)
{
strcpy(stack, "in storage, ");
stack = strchr(stack, 0);
}
if (scan->flags & FIXED)
{
strcpy(stack, "fixed in location, ");
stack = strchr(stack, 0);
}
/* fix trailing ,'s */
stack -= 2;
*stack++ = '.';
*stack++ = '\n';
*stack = 0;
}
else
{
strcpy(stack, "Robot has no flag settings.\n");
stack = strchr(stack, 0);
}
/* actions */
if (scan->max_moves)
{
sprintf(stack, "Robot has %d defined moves, which are:\n", scan->max_moves);
stack = strchr(stack, 0);
for (movescan = scan->moves_top; movescan; movescan = movescan->next)
{
sprintf(stack, " %s\n", movescan->move_string);
stack = strchr(stack, 0);
}
}
else
{
strcpy(stack, "Robot has no defined moves.\n");
stack = strchr(stack, 0);
}
*stack++ = '\n';
}
sprintf(stack, LINE "\n");
stack = end_string(stack);
if (count == 0)
{
tell_player(p, " Sorry - No robots found!\n");
stack = oldstack;
return;
}
pager(p, oldstack);
stack = oldstack;
}
/* routine for finding a random adjacent room */
int go_random_exit(player * p)
{
char *exits, *scan, *oldstack;
int count = 0, temp = 0;
oldstack = stack;
if (!p->location)
return 0;
if (!decompress_room(p->location))
return 0;
exits = p->location->exits.where;
if (!exits)
return 0;
while (*exits)
{
while (*exits && *exits != '\n')
*stack++ = *exits++;
if ((*exits) == '\n')
exits++;
*stack++ = 0;
count++;
}
temp = count;
/* now we choose the nTH exits */
temp = rand() % count;
for (scan = oldstack; temp > 0; temp--)
scan = end_string(scan);
trans_fn(p, scan);
stack = oldstack;
return 1;
}
/* routine for finding a random adjacent room */
int go_local_random_exit(player * p)
{
char *exits, *scan, *oldstack, *tstack;
int count = 0, temp = 0;
oldstack = stack;
if (!p->location)
return 0;
if (!decompress_room(p->location))
return 0;
exits = p->location->exits.where;
if (!exits)
return 0;
/* same as above routine, but only counts the same-owner type rooms */
while (*exits)
{
tstack = stack;
/* get the room owner onto the stack */
while (*exits && *exits != '.')
*stack++ = *exits++;
*stack = 0;
/* check the name */
if (!strcasecmp(tstack, p->location->owner->lower_name))
{
/* now the actual room name part */
while (*exits && *exits != '\n')
*stack++ = *exits++;
if ((*exits) == '\n')
exits++;
*stack++ = 0;
count++;
}
else
{
while (*exits && *exits != '\n')
exits++;
if (*exits == '\n')
exits++;
stack = tstack;
}
}
temp = count;
if (temp == 0)
return 0;
/* now we choose the nTH exits */
temp = rand() % count;
for (scan = oldstack; temp > 0; temp--)
scan = end_string(scan);
trans_fn(p, scan);
stack = oldstack;
return 1;
}
/* we want p for location and nonselection */
player *random_player_in_room(player * p)
{
int count = 0, chosen;
player *scan;
/* is there a location to check? */
if (!p->location || !p->location->players_top)
return p;
/* count the non-me players */
for (scan = p->location->players_top; scan; scan = scan->room_next)
if (scan != p)
count++;
/* return p if there isnt anyone else */
if (count < 1)
return p;
/* choose a random one */
chosen = (rand() % count);
scan = p->location->players_top;
if (scan == p)
scan = scan->room_next;
while (chosen)
{
chosen--;
scan = scan->room_next;
if (scan == p)
scan = scan->room_next;
}
if (scan)
return scan;
return p;
}
/* we want p for location and nonselection */
player *random_player_on_program(player * p)
{
int chosen;
player *scan;
/* count the non-me players */
/*for(scan = flatlist_start; scan; scan = scan->flat_next)
if(scan!=p)
count++; use this if the below code fails */
/* return p if there isnt anyone else */
if ((current_players - 1) < 1)
return p;
/* choose a random one */
chosen = (rand() % (current_players - 1));
scan = flatlist_start;
if (scan == p)
scan = scan->flat_next;
while (chosen)
{
chosen--;
scan = scan->flat_next;
if (scan == p)
scan = scan->flat_next;
}
if (scan)
return scan;
return p;
}
/* truly nasty. a thing to parse a robot string now that it can choose a
local or global user at random into its ibuffer. dodgy. */
/* actually, dodgy are a good band, but im listening to the cure right now
flicker flicker flicker flicker here you are
flicker flicker flicker flicker cateripillar girl. etc. */
/* yeah James, you always were a bit of a nutter :o) -- Silver */
void parse_move_into_ibuffer(player * p, char *str)
{
char *scan, *oldstack;
player *chosen;
oldstack = stack;
/* and - the immortal for statement! */
for (scan = str; scan && *scan; scan++)
{ /* check it all. */
switch (*scan)
{
case '*': /* i dont care if this means robots cannot do * signs. */
/* random user on program */
chosen = random_player_on_program(p);
if (chosen)
{
strcpy(stack, chosen->name);
stack = strchr(stack, 0);
}
break;
case '~':
/* random user in same location */
chosen = random_player_in_room(p);
if (chosen)
{
strcpy(stack, chosen->name);
stack = strchr(stack, 0);
}
break;
default:
*stack++ = *scan;
}
}
*stack++ = 0;
strncpy(p->ibuffer, oldstack, IBUFFER_LENGTH - 2);
stack = oldstack;
}
/* choose a random action according to flags and do it */
void run_action(robot * robby)
{
int count;
move *scan;
/* its time for the robot to -do- something */
/* will it be a move or something said? */
/* 50/50 chance methinks */
if (((rand() % 3 > 0) || (robby->flags & FIXED)) && robby->max_moves > 0)
{
for (count = (rand() % robby->max_moves), scan = robby->moves_top; count > 0; count--, scan = scan->next);
/* new function!
strcpy(robby->actual_player->ibuffer, scan->move_string); */
parse_move_into_ibuffer(robby->actual_player, scan->move_string);
input_for_one(robby->actual_player);
}
else
/* ie a move to a random adjacent room */
{
if (robby->flags & WANDER)
go_random_exit(robby->actual_player);
else
go_local_random_exit(robby->actual_player);
}
}
/* disconnect a robot and stop it running :-) */
void store_robot(player * p, char *str)
{
robot *robscan;
char *oldstack;
player *robby;
if (!*str)
{
tell_player(p, " Format: store <robot name>\n");
return;
}
oldstack = stack;
robscan = robot_start;
while (robscan)
{
if (!strcasecmp(robscan->lower_name, str))
{
if (robscan->flags & STORED)
{
tell_player(p, " That robot is already in storage.\n");
return;
}
robscan->flags |= STORED;
/* if the robot is connected, kill it */
robby = find_player_absolute_quiet(robscan->lower_name);
if (robby)
{
quit(robby, "");
TELLPLAYER(p, " Robot '%s' is now in storage.\n", robscan->lower_name);
SW_BUT(p, " -=*> %s stores robot '%s'\n", p->name, robscan->lower_name);
LOGF("robot", "%s stores '%s'", p->name, robscan->lower_name);
return;
}
}
robscan = robscan->next;
}
/* no robot was found */
sprintf(stack, " Sorry, no such robot '%s'.\n", str);
stack = end_string(stack);
tell_player(p, oldstack);
stack = oldstack;
}
/* connect a robot and start it running :-) */
void unstore_robot(player * p, char *str)
{
robot *robscan;
char *oldstack;
if (!*str)
{
tell_player(p, " Format: unstore <robot name>\n");
return;
}
oldstack = stack;
robscan = robot_start;
while (robscan)
{
if (!strcasecmp(robscan->lower_name, str))
{
robscan->counter = 1;
if (!(robscan->flags & STORED))
{
tell_player(p, " That robot is already running.\n");
return;
}
robscan->flags &= ~STORED;
TELLPLAYER(p, " Robot '%s' is now out of storage.\n", robscan->lower_name);
SW_BUT(p, " -=*> %s unstores robot '%s'\n", p->name, robscan->lower_name);
LOGF("robot", "%s unstores '%s'", p->name, robscan->lower_name);
return;
}
robscan = robscan->next;
}
/* no robot was found */
sprintf(stack, " Sorry, no such robot '%s'.\n", str);
stack = end_string(stack);
tell_player(p, oldstack);
stack = oldstack;
}
/* a version of connect_to_prog specifically for robots :-) */
void connect_robot_to_prog(player * p, char *name)
{
player *cp;
cp = current_player;
current_player = p;
tell_player(p, "\377\373\031"); /* send will EOR */
p->timer_count = 60;
p->timer_fn = login_timeout;
current_player = cp;
restore_player(p, name);
p->residency |= ROBOT_PRIV;
p->flags |= ROBOT;
strcpy(p->inet_addr, "0.0.0.0");
strcpy(p->num_addr, "0.0.0.0");
link_to_program(p);
}
/* next two functions are for parse.c */
void process_robot_counters(void)
{
robot *rscan;
if (sys_flags & PANIC)
return;
for (rscan = robot_start; rscan; rscan = rscan->next)
if (rscan->counter > 0)
rscan->counter--;
}
/* scan all robots and run them if necessary - this is a parse.c bit that
gets called in timer_function */
void process_robots(void)
{
robot *rscan;
player *rc;
if (sys_flags & PANIC)
return;
for (rscan = robot_start; rscan; rscan = rscan->next)
{
/* SPANG - MOVE THIS SOMEWHERE ELSE AND DO IT JUST ONCE? */
/* check to make sure robot hasnt fallen off :-) */
if (rscan->counter == 0 && !(rscan->flags & STORED))
{
rc = find_player_absolute_quiet(rscan->lower_name);
/* check for nightmare crashes/etc ;) */
if (!rc)
{
rc = create_player();
rc->fd = -1;
connect_robot_to_prog(rc, rscan->lower_name);
rscan->actual_player = rc;
}
else if (!(rc->flags & PANIC))
{
/* be cheeky here, safetly thing really. set actual_player to rc!
this is actually because i --KNOW-- someone will try logging in
as a robot and that could conceivably blow it away. */
rscan->actual_player = rc;
rscan->counter = rscan->speed;
current_player = rscan->actual_player;
current_room = rscan->actual_player->location;
run_action(rscan);
current_player = 0;
current_room = 0;
}
}
}
}
void robot_version(void)
{
sprintf(stack, " -=*> Robots v%s (by Slaine) enabled.\n", ROB_VERS);
stack = strchr(stack, 0);
#ifdef INTELLIBOTS
intelli_version();
#endif
}
void bot_unstore_robot(char *str)
{
robot *robscan;
char *oldstack;
oldstack = stack;
robscan = robot_start;
while (robscan)
{
if (!strcasecmp(robscan->lower_name, str))
{
robscan->counter = 1;
if (!(robscan->flags & STORED))
return;
robscan->flags &= ~STORED;
return;
}
robscan = robscan->next;
}
}