/* * misc.c Multiple small utility procedures */ #include "include.h" extern randData; extern server_hook; /*************************************************************************** / FUNCTION NAME: Do_init_mutex(pthread_mutex_t *the_mutex) / / FUNCTION: Initializes the passed mutex / / AUTHOR: Brian Kelly, 4/19/99 / / ARGUMENTS: / pthread_mutex_t the_mutex - The mutex to be initialized / / RETURN VALUE: none / / DESCRIPTION: / Procedure handles errors from mutex operations. / ****************************************************************************/ Do_init_mutex(pthread_mutex_t *the_mutex) { char error_msg[SZ_ERROR_MESSAGE]; int error; /* initialize the passed mutex */ error = pthread_mutex_init(the_mutex, NULL); if (error) { sprintf(error_msg, "[0.0.0.0:?] pthread_mutex_init failed with %d return code in Do_init_mutex.\n", error); Do_log_error(error_msg); exit(MUTEX_INIT_ERROR); } } /*************************************************************************** / FUNCTION NAME: Do_destroy_mutex(pthread_mutex_t *the_mutex) / / FUNCTION: Initializes the passed mutex / / AUTHOR: Brian Kelly, 4/19/99 / / ARGUMENTS: / pthread_mutex_t the_mutex - The mutex to be destroyed / / RETURN VALUE: none / / DESCRIPTION: / Procedure handles errors from mutex operations. / ****************************************************************************/ void Do_destroy_mutex(pthread_mutex_t *the_mutex) { char error_msg[SZ_ERROR_MESSAGE]; int error; /* destroy the passed mutex */ error = pthread_mutex_destroy(the_mutex); if (error) { sprintf(error_msg, "[0.0.0.0:?] pthread_mutex_destroy failed with %d return code in Do_destroy_mutex.\n", error); Do_log_error(error_msg); exit(MUTEX_DESTROY_ERROR); } } /*************************************************************************** / FUNCTION NAME: Do_lock_mutex(pthread_mutex_t *the_mutex) / / FUNCTION: Locks the passed mutex / / AUTHOR: Brian Kelly, 4/19/99 / / ARGUMENTS: / pthread_mutex_t the_mutex - The mutex to be locked / / RETURN VALUE: none / / DESCRIPTION: / Procedure handles errors from mutex operations. / ****************************************************************************/ void Do_lock_mutex(pthread_mutex_t *the_mutex) { char error_msg[SZ_ERROR_MESSAGE]; int error; #ifdef MUTEX_DEBUG sprintf(error_msg, "Request mutex %x lock.\n", the_mutex); Do_log(DEBUG_LOG, error_msg); #endif /* lock the passed mutex */ error = pthread_mutex_lock(the_mutex); if (error) { sprintf(error_msg, "[?:?] pthread_mutex_lock failed with %d return code in Do_lock_mutex.\n", error); Do_log_error(error_msg); exit(MUTEX_LOCK_ERROR); } #ifdef MUTEX_DEBUG sprintf(error_msg, "Mutex %x locked.\n", the_mutex); Do_log(DEBUG_LOG, error_msg); #endif } /*************************************************************************** / FUNCTION NAME: Do_unlock_mutex(pthread_mutex_t *the_mutex) / / FUNCTION: Unlocks the passed mutex / / AUTHOR: Brian Kelly, 4/19/99 / / ARGUMENTS: / pthread_mutex_t the_mutex - The mutex to be unlocked / / RETURN VALUE: none / / DESCRIPTION: / Procedure handles errors from mutex operations. / ****************************************************************************/ void Do_unlock_mutex(pthread_mutex_t *the_mutex) { char error_msg[SZ_ERROR_MESSAGE]; int error; /* unlock the passed mutex */ error = pthread_mutex_unlock(the_mutex); if (error) { sprintf(error_msg, "[?:?] pthread_mutex_unlock failed with a %d return code in Do_unlock_mutex.\n", error); Do_log_error(error_msg); exit(MUTEX_UNLOCK_ERROR); } #ifdef MUTEX_DEBUG sprintf(error_msg, "Mutex %x unlocked.\n", the_mutex); Do_log(DEBUG_LOG, error_msg); #endif } /*************************************************************************** / FUNCTION NAME: void *Do_malloc(struct size_t the_size) / / FUNCTION: Returns the pointer to a new memory space / / AUTHOR: Brian Kelly, 4/20/99 / / ARGUMENTS: / struct size_t the_size - The size of the memory space to allocate / / RETURN VALUE: / void * - pointer to the new memory space / / DESCRIPTION: / Procedure handles errors for malloc calls. / ****************************************************************************/ void *Do_malloc(size_t the_size) { void *void_ptr; char error_msg[SZ_ERROR_MESSAGE]; /* create the new memory space */ void_ptr = malloc(the_size); if (void_ptr == NULL) { sprintf(error_msg, "[?:?] malloc failed on size %d in Do_malloc.\n", the_size); Do_log_error(error_msg); exit(MALLOC_ERROR); } } /************************************************************************ / / FUNCTION NAME: int Do_random(void) / / FUNCTION: return a random floating point number from 0.0 < 1.0 / / AUTHOR: E. A. Estes, 2/7/86 / Brian Kelly, 4/20/99 / / ARGUMENTS: none / / RETURN VALUE: none / / MODULES CALLED: random() / / GLOBAL INPUTS: none / / GLOBAL OUTPUTS: none / / DESCRIPTION: / Convert random integer from library routine into a floating / point number, and divide by the largest possible random number. / We mask large integers with 32767 to handle sites that return / 31 bit random integers. / *************************************************************************/ int Do_random() { char error_msg[SZ_ERROR_MESSAGE]; int error, result; if (error = random_r((struct random_data *)&randData, &result)) { sprintf(error_msg, "[?:?] random_r failed with error code of %d in Do_random.\n", error); Do_log_error(error_msg); } /* return an unsigned 4 byte number */ return result; } /************************************************************************ / / FUNCTION NAME: Do_name_location(struct client_t *c) / / FUNCTION: return a formatted description of location / / AUTHOR: E. A. Estes, 12/4/85 / / ARGUMENTS: / struct player playerp - pointer to player structure / bool shortflag - set if short form is desired / / RETURN VALUE: pointer to string containing result / / MODULES CALLED: fabs(), floor(), sprintf(), distance() / / DESCRIPTION: / Look at coordinates and return an appropriately formatted / string. / *************************************************************************/ Do_name_location(struct client_t *c) { int quadrant; /* quandrant of grid */ char error_msg[SZ_ERROR_MESSAGE]; char *nametable[4][4] = /* names of places */ { "Anorien", "Ithilien", "Rohan", "Lorien", "Gondor", "Mordor", "Dunland", "Rovanion", "South Gondor", "Khand", "Eriador", "The Iron Hills", "Far Harad", "Near Harad", "The Northern Waste", "Rhun" }; if (c->player.location == PL_REALM) { if (c->player.beyond) { strcpy(c->player.area, "The Point of No Return"); } else if (c->player.circle >= 400.0) strcpy(c->player.area, "The Ashen Mountains"); else if (c->player.circle >= 100) strcpy(c->player.area, "Kennaquahir"); else if (c->player.circle >= 36) strcpy(c->player.area, "Morannon"); else if ((c->player.circle == 27) || (c->player.circle == 28)) strcpy(c->player.area, "The Cracks of Doom"); else if ((c->player.circle > 24) && (c->player.circle < 31)) strcpy(c->player.area, "The Plateau of Gorgoroth"); else if (c->player.circle >= 20) strcpy(c->player.area, "The Dead Marshes"); else if (c->player.circle >= 10) strcpy(c->player.area, "The Outer Waste"); else if (c->player.circle >= 5) strcpy(c->player.area, "The Moors Adventurous"); else { /* this expression is split to prevent compiler loop with some compilers */ quadrant = ((c->player.x > 0.0) ? 1 : 0); quadrant += ((c->player.y >= 0.0) ? 2 : 0); strcpy(c->player.area, nametable[((int) c->player.circle) - 1][quadrant]); } } else if (c->player.location == PL_THRONE) { strcpy(c->player.area, "The Lord's Chamber"); } else if (c->player.location == PL_EDGE) { strcpy(c->player.area, "Edge Of The Realm"); } else if (c->player.location == PL_VALHALLA) { strcpy(c->player.area, "Valhalla"); } else if (c->player.location == PL_PURGATORY) { strcpy(c->player.area, "Purgatory"); } /* no other places to be */ else { strcpy(c->player.area, "State Of Insanity"); sprintf(error_msg, "[%s] Bad c->player.area of %hd in Do_name_location.\n", c->connection_id, c->player.area); } } /************************************************************************ / / FUNCTION NAME: Do_truncstring() / / FUNCTION: truncate trailing blanks off a string / / AUTHOR: E. A. Estes, 12/4/85 / Brian Kelly, 5/4/99 / / ARGUMENTS: / char *string - pointer to null terminated string / / RETURN VALUE: none / / MODULES CALLED: strlen() / / DESCRIPTION: / Put nul characters in place of spaces at the end of the string. / *************************************************************************/ Do_truncstring(char *string) { int length; /* length of string */ length = strlen(string); while (length && !isgraph(string[--length])) string[length] = '\0'; } /************************************************************************ / / FUNCTION NAME: Do_distance() / / FUNCTION: calculate distance between two points / / AUTHOR: E. A. Estes, 12/4/85 / Brian Kelly, 6/20/99 / / ARGUMENTS: / double x1, y1 - x, y coordinates of first point / double x2, y2 - x, y coordinates of second point / / RETURN VALUE: distance between the two points / / MODULES CALLED: sqrt() / / GLOBAL INPUTS: none / / GLOBAL OUTPUTS: none / / DESCRIPTION: / This function is provided because someone's hypot() library function / fails if x1 == x2 && y1 == y2. / *************************************************************************/ Do_distance(double x1, double x2, double y1, double y2, double *answer) { double deltax, deltay; deltax = x1 - x2; deltay = y1 - y2; *answer = sqrt(deltax * deltax + deltay * deltay); return; } /************************************************************************ / / FUNCTION NAME: Do_move(struct client_t c, float new_x, float new_y, int operation) / / FUNCTION: truncate trailing blanks off a string / / AUTHOR: E. A. Estes, 12/4/85 / Brian Kelly, 5/8/99 / / ARGUMENTS: / char *string - pointer to null terminated string / / RETURN VALUE: none / / MODULES CALLED: strlen() / / DESCRIPTION: / Put nul characters in place of spaces at the end of the string. / *************************************************************************/ Do_move(struct client_t *c, struct event_t *the_event) { struct event_t *event_ptr, *event_ptr_two, **event_ptr_ptr; struct realm_object_t *object_ptr, **object_ptr_ptr; struct game_t *game_ptr; double dtemp, x = 0, y = 0; double distance; bool pause = FALSE; char error_msg[SZ_ERROR_MESSAGE]; long answer; short oldLocation; /* determine the destination coordinates */ switch (the_event->arg3) { case A_NEAR: the_event->arg1 = c->player.x; the_event->arg2 = c->player.y; dtemp = (double) Do_maxmove(c); Do_move_close(&the_event->arg1, &the_event->arg2, dtemp); break; case A_FAR: /* pick random coordinates far */ the_event->arg1 = SGN(c->player.x) * (D_CIRCLE + fabs(c->player.x)) * (2 * RND() + 2); the_event->arg2 = SGN(c->player.y) * (D_CIRCLE + fabs(c->player.y)) * (2 * RND() + 2); break; case A_TRANSPORT: /* send out aways */ Do_move_close(&x, &y, 2000 * RND()); /* use whichever x is larger of old and new */ if (fabs(c->player.x) > fabs(x)) { the_event->arg1 = c->player.x; } else { the_event->arg1 = x; } /* use whichever y is larger of old and new */ if (fabs(c->player.y) > fabs(y)) { the_event->arg2 = c->player.y; } else { the_event->arg2 = y; } break; case A_OUST: /* send out aways more */ Do_move_close(&x, &y, 50000 * RND()); /* use whichever x is larger of old and new */ if (fabs(c->player.x) > fabs(x)) { the_event->arg1 = c->player.x; } else { the_event->arg1 = x; } /* use whichever y is larger of old and new */ if (fabs(c->player.y) > fabs(y)) { the_event->arg2 = c->player.y; } else { the_event->arg2 = y; } break; /* send beyond */ case A_BANISH: if (fabs(c->player.x) > fabs(c->player.y)) { the_event->arg1 = c->player.x; the_event->arg2 = c->player.y; if (fabs(c->player.x) < D_BEYOND) { the_event->arg1 = SGN(c->player.x) * D_BEYOND; } } else { the_event->arg1 = c->player.x; the_event->arg2 = c->player.y; if (fabs(c->player.y) < D_BEYOND) { the_event->arg2 = SGN(c->player.y) * D_BEYOND; } } break; } /* round the new location down */ the_event->arg1 = floor(the_event->arg1); the_event->arg2 = floor(the_event->arg2); /* lock the realm */ Do_lock_mutex(&c->realm->realm_lock); /* check to make sure there are no it_combat events not received */ if (Do_check_encountered(c)) { Do_unlock_mutex(&c->realm->realm_lock); c->stuck = TRUE; return; } /* the move is successful - handle any events in the queue */ /* only orphan events if the player is leaving the square - this closes the king safe send through deliberate itcombat */ if (the_event->arg1 != c->player.x || the_event->arg2 != c->player.y) { Do_orphan_events(c); } /* if returning from beyond */ if (the_event->arg3 != A_FORCED && c->player.beyond && fabs(the_event->arg1) < D_BEYOND && fabs(the_event->arg2) < D_BEYOND) { /* cannot move back from point of no return */ /* pick the largest coordinate to remain unchanged */ if (fabs(c->player.x) > fabs(c->player.y)) { the_event->arg1 = SGN(c->player.x) * D_BEYOND; /* if (fabs(c->player.x) < D_BEYOND) { the_event->arg1 = SGN(c->player.x) * D_BEYOND; } */ } else { the_event->arg2 = SGN(c->player.y) * D_BEYOND; /* if (fabs(c->player.y) < D_BEYOND) { the_event->arg2 = SGN(c->player.y) * D_BEYOND; } */ } } /* see if the player is beyond */ c->player.beyond = FALSE; oldLocation = c->player.location; if (fabs(the_event->arg1) >= D_BEYOND || fabs(the_event->arg2) >= D_BEYOND) { c->player.beyond = TRUE; } /* if moving off the board's edge */ if (fabs(the_event->arg1) >= D_EDGE || fabs(the_event->arg2) >= D_EDGE) { /* stop a character at the edge */ /* send over if they move that way again */ if ((fabs(the_event->arg1) > D_EDGE || fabs(the_event->arg2) > D_EDGE) && c->player.location == PL_EDGE && (the_event->arg3 == A_SPECIFIC || the_event->arg3 == A_TELEPORT)) { Do_unlock_mutex(&c->realm->realm_lock); event_ptr = (struct event_t *) Do_create_event(); event_ptr->type = DEATH_EVENT; event_ptr->arg3 = K_FELL_OFF; Do_file_event(c, event_ptr); return; } c->player.location = PL_EDGE; if (fabs(the_event->arg1) > D_EDGE) { the_event->arg1 = SGN(the_event->arg1) * D_EDGE; } if (fabs(the_event->arg2) > D_EDGE) { the_event->arg2 = SGN(the_event->arg2) * D_EDGE; } } else { c->player.location = PL_REALM; } /* see if we're in the throne room */ if (the_event->arg1 == 0 && the_event->arg2 == 0) { /* if this player is not the king/steward */ if (c->game != c->realm->king) { /* if this player believes himself to be, quit */ /* we will have an event pending */ if (c->player.special_type == SC_STEWARD || c->player.special_type == SC_KING) { Do_unlock_mutex(&c->realm->realm_lock); return; } /* if this character is to be steward */ if (c->player.level >= 10 && c->player.level < 200) { /* and if this player has a staff */ if (c->player.crowns) { /* and there is no king */ if (!c->realm->king_flag) { /* enter the throne room */ c->player.location = PL_THRONE; /* if there is a steward currently on the throne */ if (c->realm->king != NULL && c->realm->king->x == 0 && c->realm->king->y == 0) { /* do nothing. If victorious, he'll be crowned in the it_combat routines */ } else { /* become steward */ Do_send_self_event(c, STEWARD_EVENT); } } /* there is a king when we're trying to be steward */ else { Do_send_line(c, "There is no need for a steward while a king presides!\n"); pause = TRUE; Do_move_close(&the_event->arg1, &the_event->arg2, Do_maxmove(c)); } } /* if the (10-200) player has no staff */ else { Do_send_line(c, "You require a staff to enter The Lord's Chamber.\n"); pause = TRUE; Do_move_close(&the_event->arg1, &the_event->arg2, Do_maxmove(c)); } } /* if this character is to be king */ else if (c->player.level >= MIN_KING && c->player.level < MAX_KING) { /* and if this player has a crown */ if (c->player.crowns) { /* enter the throne room */ c->player.location = PL_THRONE; /* if there is a king currently on the throne */ if (c->realm->king != NULL && c->realm->king->x == 0 && c->realm->king->y == 0) { /* if that character is a king */ if (c->realm->king_flag) { /* do nothing. If victorious, he'll be crowned in the it_combat routines */ } else { /* make the curent steward virtual */ c->realm->king->virtual = TRUE; /* take the throne */ Do_send_self_event(c, KING_EVENT); } } else { /* become king */ Do_send_self_event(c, KING_EVENT); } } /* if the (1000-2000) player has no crown */ else { Do_send_line(c, "You require a crown to enter The Lord's Chamber.\n"); pause = TRUE; Do_move_close(&the_event->arg1, &the_event->arg2, Do_maxmove(c)); } } /* the character is above the king level */ else if (c->player.level >= 2000) { Do_send_line(c, "The head page says, 'Get out of here, you greedy bastard.' and throws you out of The Lord's Chamber.\n"); pause = TRUE; Do_move_close(&the_event->arg1, &the_event->arg2, Do_maxmove(c)); } /* the character is of the wrong level */ else { Do_send_line(c, "The head page stops you and says, 'Characters of your level may not enter The Lord's Chamber.'\n"); pause = TRUE; Do_move_close(&the_event->arg1, &the_event->arg2, Do_maxmove(c)); } } /* if the player already is king or steward */ else { c->player.location = PL_THRONE; } } /* check for possible combat */ dtemp = FALSE; game_ptr = c->realm->games; while (game_ptr != NULL) { if (game_ptr->description != NULL && !game_ptr->virtual && game_ptr->x == the_event->arg1 && game_ptr->y == the_event->arg2 && game_ptr != c->game) { dtemp = TRUE; break; } game_ptr = game_ptr->next_game; } /* if we've encountered someone */ if (dtemp) { /* confirm the move if player moved under own power */ if (event_ptr->arg3 == A_SPECIFIC || event_ptr->arg3 == A_TELEPORT) { /* release the realm */ Do_unlock_mutex(&c->realm->realm_lock); pause = FALSE; Do_send_line(c, "The square you're moving into is currently occupied by another player. Do you still wish to move there?\n"); if (Do_yes_no(c, &answer) != S_NORM || answer == 1) { /* abort the move if the player says "no" */ Do_send_clear(c); c->player.location = oldLocation; return; } Do_send_clear(c); /* relock the realm */ Do_lock_mutex(&c->realm->realm_lock); /* see if someone else has attacked this player */ if (Do_check_encountered(c)) { Do_unlock_mutex(&c->realm->realm_lock); c->stuck = TRUE; return; } /* make sure a player is still there */ dtemp = 0; game_ptr = c->realm->games; while (game_ptr != NULL) { if (game_ptr->description != NULL && !game_ptr->virtual && game_ptr->x == the_event->arg1 && game_ptr->y == the_event->arg2 && game_ptr != c->game) { dtemp = 1; break; } game_ptr = game_ptr->next_game; } } } /* set public and private variables to the new coordinates */ if (c->wizard > 2) { c->player.location = PL_VALHALLA; } Do_location(c, the_event->arg1, the_event->arg2, FALSE); /* move the grail if player teleported close to it */ /* if (the_event->arg3 == A_TELEPORT) { object_ptr = c->realm->objects; while (object_ptr != NULL) { if (object_ptr->type == HOLY_GRAIL) { break; } object_ptr = object_ptr->next_object; } if (object_ptr == NULL) { Do_unlock_mutex(&c->realm->realm_lock); sprintf(error_msg, "[%s] No grail found in realm objects in Do_move.\n", c->connection_id); Do_log_error(error_msg); return; } Do_distance(c->player.x, object_ptr->x, c->player.y, object_ptr->y, &distance); if (distance <= c->player.level / 500.0) { sprintf(error_msg, "Teleporting grail.\n"); Do_log_error(error_msg); free((void *)object_ptr); Do_hide_grail(c->realm, c->player.level); } } */ /* look for realm objects if destination has no players */ if (dtemp == 0) { /* if a player is cloaked, he/she can't find realm objects */ if (!c->player.cloaked) { /* check for realm objects in the new location */ object_ptr_ptr = &c->realm->objects; while(*object_ptr_ptr != NULL) { if ((*object_ptr_ptr)->x == c->player.x && (*object_ptr_ptr)->y == c->player.y) { object_ptr = *object_ptr_ptr; *object_ptr_ptr = object_ptr->next_object; event_ptr = (struct event_t *) Do_create_event(); switch (object_ptr->type) { case CORPSE: event_ptr->type = CORPSE_EVENT; /* the corpse can be cursed */ event_ptr->arg1 = TRUE; event_ptr->arg4 = object_ptr->arg1; break; case HOLY_GRAIL: event_ptr->type = GRAIL_EVENT; Do_hide_grail(c->realm, c->player.level); break; case ENERGY_VOID: event_ptr->type = ENERGY_VOID_EVENT; break; case TREASURE_TROVE: event_ptr->type = TROVE_EVENT; Do_hide_trove(c->realm); break; default: sprintf(error_msg, "[%s] encountered realm object of type %d in Do_move.\n", c->connection_id, object_ptr->type); Do_log_error(error_msg); } Do_file_event(c, event_ptr); free((void *)object_ptr); } else { object_ptr_ptr = &((*object_ptr_ptr)->next_object); } } } Do_unlock_mutex(&c->realm->realm_lock); if (pause) { Do_more(c); Do_send_clear(c); } } /* else we have found a player to fight */ else { /* pass this function with realm locked! */ Do_setup_it_combat(c, game_ptr); } return; } /************************************************************************ / / FUNCTION NAME: Do_check_weight(c) / / FUNCTION: truncate trailing blanks off a string / / AUTHOR: E. A. Estes, 12/4/85 / Brian Kelly, 5/16/99 / / ARGUMENTS: / char *string - pointer to null terminated string / / RETURN VALUE: none / / MODULES CALLED: strlen() / / DESCRIPTION: / Put nul characters in place of spaces at the end of the string. / *************************************************************************/ Do_check_weight(struct client_t *c) { Do_speed(c, c->player.max_quickness, c->player.quicksilver, c->battle.speedSpell, FALSE); } /************************************************************************ / / FUNCTION NAME: Do_medic(struct client_t *c) / / FUNCTION: do random stuff / / AUTHOR: E. A. Estes, 3/3/86 / Brian Kelly, 6/20/99 / / ARGUMENTS: none / / RETURN VALUE: none / / MODULES CALLED: collecttaxes(), floor(), wmove(), drandom(), infloat(), / waddstr(), mvprintw(), getanswer() / / GLOBAL INPUTS: Player, *stdscr, *Statptr / / GLOBAL OUTPUTS: Player / / DESCRIPTION: / Handle gurus, medics, etc. / *************************************************************************/ Do_medic(struct client_t *c) { double gold; char string_buffer[SZ_LINE]; float ftemp; if (c->player.blind) { Do_send_line(c, "You've found a medic!\n"); if (Do_double_dialog(c, &gold, "How much will you offer to heal your blindness?\n")) { Do_send_clear(c); return; } /* negative gold, or more than available */ if (gold < 0.0 || gold > c->player.gold) { Do_send_line(c, "He was not amused, and gave you a disease.\n"); Do_adjusted_poison(c, 1.0); Do_strength(c, c->player.max_strength, c->player.sword, 0, FALSE); } else if (gold < c->player.level * 10) { Do_send_line(c, "Sorry, he thinks you're too powerful an adventurer to be offering him so little.\n"); } else if (RND() > (gold + 1.0) / (c->player.gold + 4.0)) { /* medic wants nearly all of available gold */ Do_send_line(c, "Sorry, he wasn't interested.\n"); } else { Do_send_line(c, "He accepted.\n"); c->player.blind = FALSE; Do_gold(c, -gold, FALSE); } Do_more(c); Do_send_clear(c); } else if (c->player.poison > 0.0) { Do_send_line(c, "You've found a medic!\n"); if (Do_double_dialog(c, &gold, "How much will you offer to be cured?\n")) { Do_send_clear(c); return; } /* negative gold, or more than available */ if (gold < 0.0 || gold > c->player.gold) { Do_send_line(c, "He was not amused, and made you worse.\n"); Do_adjusted_poison(c, 1.0); Do_strength(c, c->player.max_strength, c->player.sword, 0, FALSE); } /* medic needs at least a certain amount of gold to cure */ else if (gold < c->player.level) { Do_send_line(c, "Sorry, he thinks you're too powerful an adventurer to be offering him so little.\n"); } else if (gold < pow(c->player.poison, 2.5)) { Do_send_line(c, "Sorry, you didn't offer enough to treat your virulent poison.\n"); } else if (RND() > (1 / c->player.poison) * sqrt(c->player.circle)) { Do_send_line(c, "Sorry, the medic says the poison is beyond his ability to cure. Find a better one.\n"); } else if (RND() > (1 + MAX(0, (1 - .1 * c->player.poison))) * (gold + 1.0) / (c->player.gold + 2.0)) { /* medic wants 1/2 of available gold for 1 poison */ /* as poison goes to infinity, the medic will only cure 25% of the time when player gives all gold */ Do_send_line(c, "Sorry, he wasn't interested.\n"); } else { Do_send_line(c, "He accepted.\n"); Do_poison(c, (double) -c->player.poison); Do_gold(c, -gold, FALSE); } Do_more(c); Do_send_clear(c); } } /************************************************************************ / / FUNCTION NAME: Do_tax(struct client_t *c) / / FUNCTION: Tax time! / / AUTHOR: Eugene Hung, 6/16/01 / / ARGUMENTS: none / / RETURN VALUE: none / / MODULES CALLED: none / / GLOBAL INPUTS: none / / GLOBAL OUTPUTS: none / / DESCRIPTION: / Handle tax collecting / *************************************************************************/ Do_tax(struct client_t *c) { double gold, gems; char error_msg[SZ_ERROR_MESSAGE]; /* no tax collectors in the PoNR */ if (c->player.beyond) { return; } Do_send_line(c, "You've encountered a tax collector!\n"); if ((c->player.special_type == SC_VALAR) || (c->wizard >= 3)) { Do_send_line(c, "He takes one look at you, screams, and tries to run away!\n"); Do_more(c); Do_send_line(c, "You reach out, and squish him with your little finger!\n"); Do_more(c); Do_send_clear(c); return; } else if (c->player.special_type >= SC_COUNCIL) { Do_send_line(c, "He takes one look at you and runs away screaming in terror!\n"); Do_more(c); Do_send_clear(c); return; } else if (c->player.special_type >= SC_STEWARD) { Do_send_line(c, "He bows before you and walks off.\n"); Do_more(c); Do_send_clear(c); return; } /* at 7% we'll only take if there's at least 15 of something */ if (c->player.gems >= 15.0) { Do_send_line(c, "His eyes glow at the sight of your gems. He swipes a portion of your wealth and disappears!\n"); } /* at 10% we'll only take if there's at least 10 of something */ else if (c->player.gold >= 10.0) { Do_send_line(c, "He cackles gleefully and takes some of your gold before disappearing!\n"); } else if (c->player.gems == 0.0) { Do_send_line(c, "'Ah,' he says, 'A candidate for our welfare program.' He flips you a gold piece, gives a satisfied smile, and disappears!\n"); Do_more(c); Do_send_clear(c); Do_gold(c, 1.0, FALSE); return; } else { Do_send_line(c, "He lectures, 'How can our kingdom survive when you are making such a pittance? Work harder!' then disappears!\n"); Do_more(c); Do_send_clear(c); return; } Do_more(c); Do_send_clear(c); gold = floor(c->player.gold * 0.1); Do_gold(c, -gold, FALSE); gems = floor(c->player.gems * 0.07); Do_gems(c, -gems, FALSE); gold += gems * N_GEMVALUE; /* see if there is a steward */ /* Do_lock_mutex(&c->realm->realm_lock); if (c->realm->king != NULL && c->realm->king_flag) { */ Do_unlock_mutex(&c->realm->realm_lock); Do_lock_mutex(&c->realm->kings_gold_lock); /* steward coffers are capped at 40K */ if (RND() > c->realm->steward_gold / 40000.0) { /* stewards get a maximum of 1K donation */ if (gold > 1000.0) { c->realm->steward_gold += 1000.0; gold -= 1000.0; } else { c->realm->steward_gold += gold; Do_unlock_mutex(&c->realm->kings_gold_lock); return; } } Do_unlock_mutex(&c->realm->kings_gold_lock); /* } else { Do_unlock_mutex(&c->realm->realm_lock); } */ /* add to the king's coffers */ Do_lock_mutex(&c->realm->kings_gold_lock); /* kings coffers are capped at 2M */ if (RND() > c->realm->kings_gold / 2000000.0) { /* maximum contribution of 20K */ if (gold > 20000.0) { c->realm->kings_gold += 20000.0; gold -= 20000.0; } else { c->realm->kings_gold += gold; gold = 0.0; } } Do_unlock_mutex(&c->realm->kings_gold_lock); if (gold > 0.0) { sprintf(error_msg, "[%s] Do_tax did not allocate %lf in wealth.\n", c->connection_id, gold); Do_log(DEBUG_LOG, error_msg); } return; } /************************************************************************ / / FUNCTION NAME: Do_guru(struct client_t *c) / / FUNCTION: do random stuff / / AUTHOR: E. A. Estes, 3/3/86 / Brian Kelly, 6/20/99 / / ARGUMENTS: none / / RETURN VALUE: none / / MODULES CALLED: collecttaxes(), floor(), wmove(), drandom(), infloat(), / waddstr(), mvprintw(), getanswer() / / GLOBAL INPUTS: Player, *stdscr, *Statptr / / GLOBAL OUTPUTS: Player / / DESCRIPTION: / Handle gurus, medics, etc. / *************************************************************************/ Do_guru(struct client_t *c) { float ftemp; Do_send_line(c, "You've met a Guru. . .\n"); if (RND() * c->player.sin > 1.0) { Do_send_line(c, "You disgusted him with your sins!\n"); Do_more(c); Do_send_clear(c); } else if (c->player.poison > 0.0) { Do_send_line(c, "He looked kindly upon you, and cured you.\n"); Do_more(c); Do_send_clear(c); Do_poison(c, (double) -c->player.poison); } else if ((RND() / 10 > c->player.sin) && (c->player.circle > 1)) { Do_send_line(c, "He slips something into your charm pouch as a reward for your saintly behavior!\n"); Do_mana(c, 40.0 + 15 * c->player.circle, FALSE); Do_more(c); Do_send_clear(c); c->player.charms += 1 + (c->player.circle / 20); } else { Do_send_line(c, "He rewarded you for your virtue.\n"); Do_more(c); Do_send_clear(c); Do_mana(c, 40.0 + 10 * c->player.circle, FALSE); Do_energy(c, c->player.energy + 2 + c->player.circle / 5, c->player.max_energy, c->player.shield + 2 + c->player.circle / 5, 0, FALSE); } } /************************************************************************ / / FUNCTION NAME: Do_village(struct client_t *c) / / FUNCTION: do random stuff / / AUTHOR: E. A. Estes, 3/3/86 / Brian Kelly, 6/20/99 / / ARGUMENTS: none / / RETURN VALUE: none / / MODULES CALLED: collecttaxes(), floor(), wmove(), drandom(), infloat(), / waddstr(), mvprintw(), getanswer() / / GLOBAL INPUTS: Player, *stdscr, *Statptr / / GLOBAL OUTPUTS: Player / / DESCRIPTION: / Handle gurus, medics, etc. / *************************************************************************/ Do_village(struct client_t *c) { struct event_t *event_ptr; long answer; float ftemp; if (c->player.beyond || (c->player.level + 1 < c->player.circle)) { Do_send_line(c, "You have found a village. But the inhabitants are too strong for you!\n"); Do_more(c); Do_send_clear(c); return; } Do_send_line(c, "You have found a village. Do you wish to pillage it?\n"); if (Do_yes_no(c, &answer) != S_NORM || answer == 1) { /* return if the player says no */ Do_send_clear(c); return; } Do_send_clear(c); Do_sin(c, 0.5); Do_experience(c, (.75 + RND() / 2) * 1000.0 * c->player.circle, FALSE); Do_gold(c, (.75 + RND() / 2) * 50.0 * c->player.circle, FALSE); } /************************************************************************ / / FUNCTION NAME: Do_plague(struct client_t *c, struct event_t *the_event) / / FUNCTION: do random stuff / / AUTHOR: E. A. Estes, 3/3/86 / Brian Kelly, 6/20/99 / / ARGUMENTS: none / / RETURN VALUE: none / / MODULES CALLED: collecttaxes(), floor(), wmove(), drandom(), infloat(), / waddstr(), mvprintw(), getanswer() / / GLOBAL INPUTS: Player, *stdscr, *Statptr / / GLOBAL OUTPUTS: Player / / DESCRIPTION: / Handle plague. event->arg3 contains 1000x the amount of poison to / increase the player by. / *************************************************************************/ Do_plague(struct client_t *c, struct event_t *the_event) { float ftemp; if (the_event->arg3 == 0) { if (c->player.poison < sqrt(c->player.circle)) { Do_send_line(c, "You've been hit with a plague!\n"); if (c->player.type == C_ELF) { Do_send_line(c, "But as an elf, you are unaffected!\n"); } else if (c->player.charms > 0) { Do_send_line(c, "But your charm saved you!\n"); --c->player.charms; } else { Do_adjusted_poison(c, 1.0); } if (c->player.virgin && RND() < 0.2) { Do_send_line(c, "Your virgin catches it and perishes!\n"); Do_virgin(c, FALSE, FALSE); } Do_more(c); Do_send_clear(c); } } else { Do_send_line(c, "You absorb some of the poison you cured!\n"); Do_poison(c, (double) the_event->arg3 / 1000); } } /************************************************************************ / / FUNCTION NAME: Do_volcano(struct client_t *c) / / FUNCTION: generate a place for the One Ring to be thrown into / / AUTHOR: Eugene Hung, 8/2/01 / / ARGUMENTS: c / / RETURN VALUE: none / / MODULES CALLED: / / GLOBAL INPUTS: / / GLOBAL OUTPUTS: / / DESCRIPTION: / Gives crowns / *************************************************************************/ Do_volcano(struct client_t *c) { long answer; float ftemp; char string_buffer[SZ_LINE]; Do_send_line(c, "You've come upon a pool of lava!\n"); if (c->player.ring_type != R_NONE) { Do_send_line(c, "Do you wish to destroy your ring?\n"); } else { Do_send_line(c, "It bubbles and hisses, and you wisely avoid it.\n"); Do_more(c); Do_send_clear(c); return; } if (Do_yes_no(c, &answer) != S_NORM || answer == 1) { /* return if the player says no */ Do_send_line(c, "You hang on to Your Precious Ring. You hear a roar of evil laughter in the distance.\n"); Do_sin(c, 2.5); Do_more(c); Do_send_clear(c); return; } Do_send_line(c, "Sweating, you attempt to throw the Ring in . . .\n"); Do_send_buffer(c); sleep(3); ftemp = RND(); /* certain races have more willpower */ if (((c->player.type == C_HALFLING) && (c->player.sin <= ftemp + .25)) || ((c->player.type == C_DWARF) && (c->player.sin * 2 <= ftemp + .25)) || ((c->player.type == C_ELF) && (c->player.sin * 3 <= ftemp + .25)) || (c->player.sin * 4 <= ftemp + .25) ) { Do_send_line(c, "You throw the ring into the pool...\n"); Do_more(c); Do_send_clear(c); if (c->player.ring_type == R_DLREG) { Do_send_line(c, "and watch as the symbol of ultimate evil melts in its birth place!\n"); Do_more(c); Do_send_line(c, "Having rid yourself of the One Ring, you feel a great burden lift from your heart!\n"); Do_more(c); Do_send_clear(c); Do_sin(c, -c->player.sin); Do_experience(c, 50000.0 * c->player.circle, FALSE); sprintf(string_buffer, "%s has thrown the One Ring into the Fire! Praise %s with great praise!\n", c->modifiedName, (c->player.gender ? "her" : "him")); Do_broadcast(c, string_buffer); Do_ring(c, R_NONE, FALSE); if ((c->player.level > MIN_KING) && (c->player.level < MAX_KING)) { Do_send_line(c, "For your great deed, you have been given a golden crown!\n"); Do_crowns(c, 1, FALSE); Do_more(c); } } else { Do_send_line(c, "Unfortunately, nothing else seems to happen.\n"); Do_ring(c, R_NONE, FALSE); Do_more(c); } } else { Do_send_line(c, "You lack the willpower to do so! You hear a sinister cackle in the distance.\n"); Do_sin(c, 1.0); if (c->player.ring_type == R_BAD) { c->player.ring_duration = 0; Do_ring(c, R_SPOILED, FALSE); } Do_more(c); } Do_send_clear(c); return; } /************************************************************************ / / FUNCTION NAME: Do_shutdown_check(struct client_t *c) / / FUNCTION: do random stuff / / AUTHOR: E. A. Estes, 3/3/86 / Brian Kelly, 6/20/99 / / ARGUMENTS: none / / RETURN VALUE: none / / MODULES CALLED: collecttaxes(), floor(), wmove(), drandom(), infloat(), / waddstr(), mvprintw(), getanswer() / / GLOBAL INPUTS: Player, *stdscr, *Statptr / / GLOBAL OUTPUTS: Player / / DESCRIPTION: / Handle gurus, medics, etc. / *************************************************************************/ Do_shutdown_check(struct client_t *c) { if (server_hook != RUN_SERVER && server_hook != LEISURE_SHUTDOWN) { Do_send_int(c, SHUTDOWN_PACKET); Do_send_buffer(c); c->socket_up = FALSE; } } /************************************************************************ / / FUNCTION NAME: Do_information(struct client_t *c) / / FUNCTION: do random stuff / / AUTHOR: Brian Kelly, 11/8/99 / / ARGUMENTS: none / / RETURN VALUE: none / / MODULES CALLED: collecttaxes(), floor(), wmove(), drandom(), infloat(), / waddstr(), mvprintw(), getanswer() / / GLOBAL INPUTS: Player, *stdscr, *Statptr / / GLOBAL OUTPUTS: Player / / DESCRIPTION: / Handle gurus, medics, etc. / *************************************************************************/ Do_information(struct client_t *c) { struct event_t *event_ptr; struct button_t buttons; long answer; char error_msg[SZ_ERROR_MESSAGE]; char string_buffer[SZ_LINE]; Do_clear_buttons(&buttons, 0); strcpy(buttons.button[0], "Stats\n"); strcpy(buttons.button[1], "Examine\n"); strcpy(buttons.button[2], "Players\n"); strcpy(buttons.button[3], "Scoreboard\n"); strcpy(buttons.button[4], "Channel\n"); if (c->hearBroadcasts) { strcpy(buttons.button[5], "No Announce\n"); } else { strcpy(buttons.button[5], "Announce\n"); } if (c->game->chatFilter) { strcpy(buttons.button[6], "Filter Off\n"); } else { strcpy(buttons.button[6], "Filter On\n"); } strcpy(buttons.button[7], "Cancel\n"); if (Do_buttons(c, &answer, &buttons) != S_NORM || answer == 7) { Do_send_clear(c); return; } Do_send_clear(c); event_ptr = (struct event_t *) Do_create_event(); event_ptr->to = c->game; event_ptr->from = c->game; switch (answer) { /* see this player's stats */ case 0: event_ptr->type = EXAMINE_EVENT; event_ptr->arg3 = FALSE; break; case 1: event_ptr->type = EXAMINE_EVENT; event_ptr->arg3 = TRUE; break; case 2: event_ptr->type = LIST_PLAYER_EVENT; break; case 3: Do_scoreboard(c, 0, TRUE); break; case 4: sprintf(string_buffer, "You are currently on channel %d.\n", c->channel); Do_send_line(c, string_buffer); Do_send_line(c, "Channel 8 is reserved for players with a palantir.\n"); Do_send_line(c, "Which channel do you want to change to?\n"); Do_clear_buttons(&buttons, 0); strcpy(buttons.button[0], "1\n"); strcpy(buttons.button[1], "2\n"); strcpy(buttons.button[2], "3\n"); strcpy(buttons.button[3], "4\n"); strcpy(buttons.button[4], "5\n"); strcpy(buttons.button[5], "6\n"); strcpy(buttons.button[6], "7\n"); if (c->player.palantir || c->wizard > 3) { strcpy(buttons.button[7], "8\n"); } if (Do_buttons(c, &answer, &buttons) != S_NORM) { Do_send_clear(c); free((void *)event_ptr); return; } Do_send_clear(c); /* update the player info, if necessary */ if (c->channel != (int)answer +1) { /* if we were palantiring, turn off snooping */ if (c->channel == 8) { c->game->hearAllChannels = HEAR_SELF; } c->channel = (int)answer + 1; /* if we used our palantir, turn on snooping */ if (c->channel == 8) { c->game->hearAllChannels = HEAR_ONE; } Do_lock_mutex(&c->realm->realm_lock); Do_player_description(c); Do_unlock_mutex(&c->realm->realm_lock); Do_send_specification(c, CHANGE_PLAYER_EVENT); } break; /* case 5: free((void *)event_ptr); sprintf(string_buffer, "/var/phantasia/backup2/%s", c->player.lcname); errno = 0; if ((character_file=fopen(string_buffer, "w")) == NULL) { sprintf(error_msg, "[%s] fopen of %s failed in Do_information: %s\n", c->connection_id, string_buffer, strerror(errno)); Do_log_error(error_msg); return; } errno = 0; if (fwrite((void *)&c->player, SZ_PLAYER, 1, character_file) != 1) { sprintf(error_msg, "[%s] fwrite of %s failed in Do_information: %s\n", c->connection_id, string_buffer, strerror(errno)); Do_log_error(error_msg); fclose(character_file); return; } fclose(character_file); sprintf(string_buffer, "%s has been backed up for a server crash.\n", c->modifiedName); Do_send_line(c, string_buffer); Do_send_line(c, "Backing up this character again will destroy the old backup.\n"); Do_more(c); return; */ case 5: free((void *)event_ptr); if (c->hearBroadcasts) { Do_send_line(c, "Server announcements are now blocked.\n"); c->hearBroadcasts = FALSE; } else { Do_send_line(c, "You will now hear server announcements.\n"); c->hearBroadcasts = TRUE; } Do_more(c); Do_send_clear(c); return; case 6: c->game->chatFilter = !c->game->chatFilter; return; default: sprintf(error_msg, "[%s] Returned non-option %ld in Do_information.\n", c->connection_id, answer); Do_log_error(error_msg); free((void *)event_ptr); Do_caught_hack(c, H_SYSTEM); return; } if (event_ptr->type != NULL_EVENT) { Do_handle_event(c, event_ptr); } else { free((void *)event_ptr); } return; } /************************************************************************ / / FUNCTION NAME: Do_scoreboard(struct client_t *c) / / FUNCTION: do random stuff / / AUTHOR: Brian Kelly, 12/30/99 / / ARGUMENTS: none / / RETURN VALUE: none / / MODULES CALLED: collecttaxes(), floor(), wmove(), drandom(), infloat(), / waddstr(), mvprintw(), getanswer() / / GLOBAL INPUTS: Player, *stdscr, *Statptr / / GLOBAL OUTPUTS: Player / / DESCRIPTION: / Handle gurus, medics, etc. / *************************************************************************/ Do_scoreboard(struct client_t *c, int start, int new) { char string_buffer[SZ_LINE]; char error_msg[SZ_ERROR_MESSAGE]; struct scoreboard_t scoreboard; FILE *scoreboard_file; long theEOF; int i, records, EOF_flag; Do_send_int(c, SCOREBOARD_DIALOG_PACKET); Do_lock_mutex(&c->realm->scoreboard_lock); /* open the scoreboard file */ errno = 0; if (new) { if ((scoreboard_file=fopen(SCOREBOARD_FILE, "r")) == NULL) { sprintf(error_msg, "[%s] fopen of %s failed in Do_scoreboard: %s\n", c->connection_id, SCOREBOARD_FILE, strerror(errno)); Do_log_error(error_msg); Do_send_line(c, "1\nCurrently, there is nobody on the scoreboard.\n"); Do_unlock_mutex(&c->realm->scoreboard_lock); return; } else { /* drop to next part */ } } else { if ((scoreboard_file=fopen(OLD_SCOREBOARD_FILE, "r")) == NULL) { sprintf(error_msg, "[%s] fopen of %s failed in Do_scoreboard: %s\n", c->connection_id, OLD_SCOREBOARD_FILE, strerror(errno)); Do_log_error(error_msg); Do_send_line(c, "1\nCurrently, there is nobody on the scoreboard.\n"); Do_unlock_mutex(&c->realm->scoreboard_lock); return; } else { /* drop to next part */ } } /* find the end of the scoreboard file */ fseek(scoreboard_file, 0, SEEK_END); theEOF = ftell(scoreboard_file); /* calculate how many records are in the file */ records = theEOF / SZ_SCOREBOARD; /* the earliest we can start is the beginning */ if (start < 0) { start = 0; } /* we'll only show 50 records maximum */ records = 50; /* tell the client number of records and their start */ Do_send_int(c, start); Do_send_int(c, records); /* move to the starting record */ EOF_flag = FALSE; fseek(scoreboard_file, SZ_SCOREBOARD * start, SEEK_SET); /* read the next 50 or so records */ for (i = start + 1; i < records + start + 1; i++) { if (!EOF_flag && fread((void *)&scoreboard, SZ_SCOREBOARD, 1, scoreboard_file) == 1) { /* sprintf(string_buffer, "%d> %s, the level %0.lf %s, was %s at ", i, scoreboard.name, scoreboard.level, scoreboard.class, scoreboard.how_died); */ if (scoreboard.level == 9999) { sprintf(string_buffer, "%d> %s the %s ascended to the position of Valar on ", i, scoreboard.name, scoreboard.class); Do_send_string(c, string_buffer); ctime_r(&scoreboard.time, string_buffer); Do_truncstring(string_buffer); strcat(string_buffer, ".\n"); Do_send_string(c, string_buffer); } else { sprintf(string_buffer, "%d> %s, the level %0.lf %s, %s on ", i, scoreboard.name, scoreboard.level, scoreboard.class, scoreboard.how_died); /* sprintf(string_buffer, "%d> %s, the level %0.lf %s,", i, scoreboard.name, scoreboard.level, scoreboard.class); */ Do_send_string(c, string_buffer); ctime_r(&scoreboard.time, string_buffer); Do_truncstring(string_buffer); strcat(string_buffer, ".\n"); Do_send_string(c, string_buffer); } } else { EOF_flag = TRUE; sprintf(string_buffer, "%d> No entry.\n", i); Do_send_string(c, string_buffer); } } /* close the file handles */ fclose(scoreboard_file); Do_send_buffer(c); Do_unlock_mutex(&c->realm->scoreboard_lock); } /************************************************************************ / / FUNCTION NAME: int Do_profanity_check(char *theString) / / FUNCTION: do random stuff / / AUTHOR: Brian Kelly, 1/2/01 / / ARGUMENTS: none / / RETURN VALUE: none / / MODULES CALLED: collecttaxes(), floor(), wmove(), drandom(), infloat(), / waddstr(), mvprintw(), getanswer() / / GLOBAL INPUTS: Player, *stdscr, *Statptr / / GLOBAL OUTPUTS: Player / / DESCRIPTION: / Handle gurus, medics, etc. / *************************************************************************/ int Do_profanity_check(char *theString) { char *swears[] = { "shit", "fuck", "fuc", "fuk", "fock", "piss", "cunt", "cock", "ass", "dick", "penis", "pussy", "clit", "bitch", "butt", "twat", "vagina", "dork", "dildo", "masturbat", "fag", "homo", "lesbian", "screw", "anal", "poo", "nigger", "nigga", "chink", "jap", "wop", "kike", "bitch", "whore", "crap", "hell", "damn", "rape", "suck", "abortion", "mute", "sex", "kkk", "balls", "bush", "tits", "dammit", "snatch", "sauron", "morgoth", "osama", "alatar", "stfu", "wtf", "" }; char currentChar; int stringPtr, currentSwear, swearPtr, wordBeginning, swearBeginning, spaceCount; if (theString[0] == '\0') { return FALSE; } currentSwear = 0; /* loop through all the swear words */ while (swears[currentSwear][0] != '\0') { stringPtr = swearPtr = wordBeginning = swearBeginning = spaceCount = 0; /* look for the next letter in the swear */ while (theString[stringPtr] != '\0') { currentChar = theString[stringPtr]; /* replace numbers that could be letters */ if (currentChar == '1' && swears[currentSwear][swearPtr] == 'i') { currentChar = 'i'; } else if (currentChar == '1' && swears[currentSwear][swearPtr] == 'l') { currentChar = 'l'; } else if (currentChar == 'z' && swears[currentSwear][swearPtr] == 's') { currentChar = 's'; } else if (currentChar == '5' && swears[currentSwear][swearPtr] == 's') { currentChar = 's'; } else if (currentChar == '0' && swears[currentSwear][swearPtr] == 'o') { currentChar = 'o'; } else if (currentChar == '$' && swears[currentSwear][swearPtr] == 's') { currentChar = 's'; } else if (currentChar == '@' && swears[currentSwear][swearPtr] == 'a') { currentChar = 'a'; } /* Is this character a space? */ if (currentChar == '_') { if (swearPtr == 0) { wordBeginning = stringPtr + 1; } else { ++spaceCount; } } /* If the character is not a letter, skip it */ else if (isalpha(currentChar)) { if (currentChar == swears[currentSwear][swearPtr]) { ++swearPtr; /* See if we've found a complete swear */ if (swears[currentSwear][swearPtr] == '\0') { /* if the swear did not start at the beginning of a word and contains one space, let it pass. "is_hit" would be caught */ if (wordBeginning != swearBeginning || spaceCount != 1) { return TRUE; } swearPtr = 0; spaceCount = 0; stringPtr = swearBeginning; ++swearBeginning; } } /* Start over if anything but previous swear letter */ /* This is to catch "ffuucckk" */ else if (swearPtr == 0 || currentChar != swears[currentSwear][swearPtr - 1]) { swearPtr = 0; spaceCount = 0; stringPtr = swearBeginning; ++swearBeginning; } } /* move to the next letter */ ++stringPtr; } ++currentSwear; } return FALSE; } /************************************************************************ / / FUNCTION NAME: Do_replace_profanity(struct client_t *c, char *theString) / / FUNCTION: do random stuff / / AUTHOR: Brian Kelly, 10/11/00 / / ARGUMENTS: none / / RETURN VALUE: none / / MODULES CALLED: collecttaxes(), floor(), wmove(), drandom(), infloat(), / waddstr(), mvprintw(), getanswer() / / GLOBAL INPUTS: Player, *stdscr, *Statptr / / GLOBAL OUTPUTS: Player / / DESCRIPTION: / Handle gurus, medics, etc. / *************************************************************************/ int Do_replace_profanity(char *theString) { char *swears[] = { "shit", "fock", "fuk", "fuc", "cunt", "nigger", "crap", "damn", "dammit", "@ss", "a$$", "" }; char replacements[] = "smurf "; char currentChar; int stringPos, currentSwear, swearPos, wordStart, swearStart, smurfPos; int spaceCount, bleepPos; bool profane, spaceExceptionPossible; if (theString[0] == '\0') { return FALSE; } profane = FALSE; currentSwear = 0; /* loop through all the swear words */ while (swears[currentSwear][0] != '\0') { stringPos = swearPos = wordStart = swearStart = 0; spaceExceptionPossible = FALSE; /* look until the we reach the end of the string */ while (theString[stringPos] != '\0') { currentChar = tolower(theString[stringPos]); /* Convert similar symbols */ if (currentChar == '!' && swears[currentSwear][swearPos] == 'i') { currentChar = 'i'; } else if (currentChar == '!' && swears[currentSwear][swearPos] == 'l') { currentChar = 'l'; } else if (currentChar == '1' && swears[currentSwear][swearPos] == 'i') { currentChar = 'i'; } else if (currentChar == '1' && swears[currentSwear][swearPos] == 'l') { currentChar = 'l'; } else if (currentChar == '#' && swears[currentSwear][swearPos] == 'h') { currentChar = 'h'; } else if (currentChar == '$' && swears[currentSwear][swearPos] == 's') { currentChar = 's'; } else if (currentChar == '(' && swears[currentSwear][swearPos] == 'c') { currentChar = 'c'; } /* Is this character a space? */ if (currentChar == ' ') { /* if this space is within a possible swear */ if (swearPos > 0) { /* count the space for possible exception */ ++spaceCount; } /* if we've found no swear letters */ else { /* we won't find anything before this */ wordStart = stringPos + 1; swearStart = wordStart; /* since the swear starts a word, no exception */ spaceExceptionPossible = FALSE; } /* move to the next letter of the string */ ++stringPos; continue; } /* If the character is not a letter, skip it */ else if (! isalpha(currentChar)) { ++stringPos; continue; } /* Is this character the next of this swear? */ else if (currentChar == swears[currentSwear][swearPos]) { /* start looking for the next letter */ ++swearPos; /* have we found all the swear letters? */ if (swears[currentSwear][swearPos] == '\0') { /* we don't want to bleep "is hit" or "if u c", so pass over if swear didn't start a word and there was 1 or 2 spaces */ if (!spaceExceptionPossible || spaceCount != 1) { /* bleep out the whole word */ bleepPos = wordStart; profane = TRUE; /* loop until space past current location */ while (bleepPos < stringPos || (theString[bleepPos] != ' ' && theString[bleepPos] != '\0')) { /* replace the letter */ smurfPos = bleepPos - wordStart; if (smurfPos > 4) { smurfPos = 5; } theString[bleepPos++] = replacements[smurfPos]; } if (smurfPos == 3) { theString[bleepPos + 1] = theString[bleepPos]; theString[bleepPos] = replacements[smurfPos + 1]; } /* start again at the last replacement */ /* bleepPos is a space or null, so the spaceExceptionPossible will be handled */ stringPos = bleepPos; swearPos = 0; continue; } /* this is a swear, but we're passing it over */ else { /* start one after where we did last time */ stringPos = swearStart + 1; swearPos = 0; continue; } } /* found the next swear letter */ ++stringPos; continue; } /* See if this letter is the same as the last */ /* This is to catch "ffuucckk" */ else if (swearPos != 0 && currentChar == swears[currentSwear][swearPos - 1]) { /* move to the next letter */ ++stringPos; continue; } /* different letter - start one after where we started before */ stringPos = swearStart = swearStart + 1; swearPos = 0; spaceExceptionPossible = TRUE; spaceCount = 0; } ++currentSwear; } return profane; } /************************************************************************ / / FUNCTION NAME: Do_censor(char *destString, char *sourceString) / / FUNCTION: do random stuff / / AUTHOR: Brian Kelly, 06/25/02 / / ARGUMENTS: none / / RETURN VALUE: none / / MODULES CALLED: collecttaxes(), floor(), wmove(), drandom(), infloat(), / waddstr(), mvprintw(), getanswer() / / GLOBAL INPUTS: Player, *stdscr, *Statptr / / GLOBAL OUTPUTS: Player / / DESCRIPTION: / Handle gurus, medics, etc. / *************************************************************************/ int Do_censor(char *destString, char *sourceString) { char *swears[] = { "shit", "fuck", "cunt", "nigger", "cock", "dick", "penis", "pussy", "clit", "vagina", "dildo", "masturbate", "masturbation", "anal", "chink", "kike", "tits", "" }; char substitute[8][5] = { { 'a', '@', '\0' }, { 'c', '(', '\0' }, { 'h', '#', '\0' }, { 'i', 'l', '!', '1', '\0' }, { 'l', 'i', '!', '1', '\0' }, { 'o', '0', '\0' }, { 's', '$', '5', 'z', '\0' }, { '\0' } }; int sourceLetter, swearNumber, swearLetter, letterPtr, row, column, count; bool newWordFlag, matchFlag, spaceFlag, swearFlag; char lcSource[SZ_CHAT + 64], currentLetter; /* make a lowercase version of the string */ sourceLetter = 0; do { lcSource[sourceLetter] = tolower(sourceString[sourceLetter]); } while (sourceString[sourceLetter++] != '\0'); /* start at the first letter of the source */ sourceLetter = 0; newWordFlag = TRUE; count = 0; /* run through all the characters of the source string */ while (sourceString[sourceLetter] != '\0') { /* if this character is a space */ if (sourceString[sourceLetter] == ' ') { /* no swears start with a space */ *destString++ = ' '; newWordFlag = TRUE; ++sourceLetter; continue; } /* start at the front of the list of swears */ swearFlag = FALSE; swearNumber = 0; /* loop through all the swear words */ while (swears[swearNumber][0] != '\0') { /* start with the first letter of this swear */ swearLetter = 0; /* we start checking from our current position */ letterPtr = sourceLetter; spaceFlag = FALSE; /* check the swear from this letter */ do { /* assume no match */ matchFlag = FALSE; /* convert the current character to lowercase */ currentLetter = lcSource[letterPtr]; /* if the current letter is a space and we're in the middle of a swear */ if (currentLetter == ' ' && swears[swearNumber][swearLetter] != '\0') { /* set the space flag */ spaceFlag = TRUE; /* increment to the next string character and re-loop */ ++letterPtr; continue; } /* if the letter is the next in the swear */ if (swears[swearNumber][swearLetter] == currentLetter) { /* swear matches */ matchFlag = TRUE; } /* see if a substitute character was used (swear isn't NULL) */ else if (swears[swearNumber][swearLetter] != '\0') { row = 0; /* run through the substitute list */ while (substitute[row][0] != '\0') { /* if this sub char is the next in the swear */ if (substitute[row][0] == swears[swearNumber][swearLetter]) { column = 1; /* run through the list */ while (substitute[row][column] != '\0') { /* is the string letter this replacement character? */ if (currentLetter == substitute[row][column]) { /* swear matches */ matchFlag = TRUE; break; } ++column; } /* a letter is only listed as a sub once */ break; } ++row; } } /* if this letter matches the next in the swear */ if (matchFlag) { /* move to the next letter of the string and swear */ ++letterPtr; ++swearLetter; } /* otherwise, if we're in the middle of a swear */ else if (swearLetter) { /* if the letter is a repeat of the last */ if (swears[swearNumber][swearLetter - 1] == currentLetter) { /* swear is a repeat */ matchFlag = TRUE; } /* see if it could be a substitute character repeat */ else { row = 0; /* run through the substitute list */ while (substitute[row][0] != '\0') { /* if this sub char is the previous one in the swear */ if (substitute[row][0] == swears[swearNumber][swearLetter - 1]) { column = 1; /* run through the list */ while (substitute[row][column] != '\0') { /* is the string letter this replacement character? */ if (currentLetter == substitute[row][column]) { /* swear matches */ matchFlag = TRUE; break; } ++column; } /* a letter is only listed as a sub once */ break; } ++row; } } /* if this letter matches the previous in the swear */ if (matchFlag) { /* move to the next letter of the string only */ ++letterPtr; } } } while (matchFlag); /* see if a complete swear was found */ if (swears[swearNumber][swearLetter] == '\0') { /* if the swear contains spaces and didn't start a word */ if (!newWordFlag && spaceFlag) { /* reject the word for replacement */ swearLetter = 0; } /* if the swear is valid */ else { swearFlag = TRUE; /* break out of the search, we'll replace it below */ break; } } ++swearNumber; } /* if a complete swear was found */ if (swearFlag) { /* if the original was capitalized */ if (isupper(sourceString[sourceLetter])) { /* if the second letter was uppercase */ if (isupper(sourceString[sourceLetter + 1])) { /* assume it was all uppercase */ strcpy(destString, "SMURF"); } else { /* just capitalize it */ strcpy(destString, "Smurf"); } } /* the word was lowercase */ else { /* replace the word */ strcpy(destString, "smurf"); } /* move the pointer over the replacement */ destString += 5; /* the we continue from the end of the swear */ sourceLetter = letterPtr; /* the next character is never the start of a new word */ newWordFlag = FALSE; /* increment the counter */ ++count; } /* no swear was found */ else { /* if this letter is a space */ if (sourceString[sourceLetter] == ' ') { /* the next character will be the start of a new word */ newWordFlag = TRUE; } else { newWordFlag = FALSE; } /* copy over this letter and move to the next letter */ *destString++ = sourceString[sourceLetter++]; } } /* add a null */ *destString = '\0'; /* see if this was an buffer overflow attempt */ if (count > 20) { return TRUE; } return FALSE; } /************************************************************************ / / FUNCTION NAME: int Do_spam_check(struct client_t *c, char *message) / / FUNCTION: reads the next packet type off the socket / / AUTHOR: Brian Kelly, 8/25/99 / / ARGUMENTS: / int the_socket - the socket to read the packet type / / RETURN VALUE: / int - the type of packet next on the socket / / MODULES CALLED: wmove(), _filbuf(), clearok(), waddstr(), wrefresh(), / wclrtoeol() / / DESCRIPTION: / Read a string from the keyboard. / /************************************************************************/ int Do_spam_check(struct client_t *c, char *message) { int i, count; /* move up all the previous chat times and length */ for (i = 8; i >= 0; i--) { c->chatTimes[i + 1] = c->chatTimes[i]; c->chatLength[i + 1] = c->chatLength[i]; } /* add the current moment into the lists */ c->chatTimes[0] = time(NULL); c->chatLength[0] = (int) floor(strlen(message) / 80.0); /* see if we can find a chat infraction */ for (i = 3; i < 9; i++) { /* player can send 3 + n messages every n^2 seconds */ if (c->chatTimes[0] - c->chatTimes[i] <= (i - 2) * (i - 2)) { /* tag this player as muted */ Do_caught_spam(c, H_SPAM); return TRUE; } } /* add up the lines of text from the last nine messages */ count = 0; for (i = 0; i <= 9; i++) { count += c->chatLength[i]; } printf("count check: %d.\n", count); /* if the number of lines exceeds 14 */ if (count >= 14) { /* clear the history so we don't nail them forever */ for (i = 0; i <= 9; i++) { c->chatLength[i] = 0; } /* tag this player as muted */ Do_caught_spam(c, H_FLOOD); return TRUE; } /* no problems */ return FALSE; } /****************************************************************** / / FUNCTION NAME: Do_title_page(struct client_t *c) / / FUNCTION: print title page / / AUTHOR: E. A. Estes, 12/4/85 / Brian Kelly, 5/3/99 / / ARGUMENTS: none / / RETURN VALUE: none / / MODULES CALLED: fread(), fseek(), fopen(), fgets(), wmove(), strcpy(), / fclose(), strlen(), waddstr(), sprintf(), wrefresh() / / DESCRIPTION: / Print important information about game, players, etc. / *************************************************************************/ Do_title_page(struct client_t *c) { struct game_t *game_ptr, *first_ptr, *second_ptr; short councilfound; /* set if we find a member of the council */ char string_buffer[SZ_LINE]; char error_msg[SZ_ERROR_MESSAGE]; int error; /* print a header */ Do_send_line(c, "W e l c o m e t o P h a n t a s i a (vers. 4.03)!\n"); /* lock the realm */ Do_lock_mutex(&c->realm->realm_lock); /* display the current king, if any */ if (c->realm->king == NULL || !c->realm->king_flag) { if (c->realm->king == NULL) { Do_send_line(c, "There is no ruler at this time.\n"); } else { if (c->realm->king->description != NULL) { sprintf(string_buffer, "The present steward is %s Level: %.0lf\n", c->realm->king->description->name, c->realm->king->description->level); Do_send_line(c, string_buffer); } else { sprintf(string_buffer, "[%s] Information on present steward unavailable in Do_title_page.\n", c->connection_id); Do_log_error(string_buffer); } } } else { /* make sure the character has a description in place */ if (c->realm->king->description != NULL) { /* print out the present king/queen */ if (c->realm->king->description->gender == MALE) { sprintf(string_buffer, "The present ruler is King %s Level: %.0lf\n", c->realm->king->description->name, c->realm->king->description->level); } else { sprintf(string_buffer, "The present ruler is Queen %s Level: %.0lf\n", c->realm->king->description->name, c->realm->king->description->level); } } else { sprintf(string_buffer, "[%s] Information on present ruler unavailable in Do_title_page.\n", c->connection_id); Do_log_error(string_buffer); } Do_send_line(c, string_buffer); } /* display the current valar, in any */ if (c->realm->valar_name[0] != '\0') { sprintf(string_buffer, "The Valar is %s\n", c->realm->valar_name); /* if (c->realm->valar->description != NULL) { sprintf(string_buffer, "The Valar is %s Level: %.0lf\n", c->realm->valar->description->name, c->realm->valar->description->level); } else { sprintf(string_buffer, "[%s] Information on valar unavailable in Do_title_page.\n", c->connection_id); Do_log_error(string_buffer); } */ Do_send_line(c, string_buffer); } /* search for council members */ councilfound = 0; game_ptr = c->realm->games; /* loop through all the games */ while (game_ptr != NULL && councilfound < 5) { /* if the player is playing and is on the council */ if (game_ptr->description != NULL && (game_ptr->description->special_type == SC_COUNCIL || game_ptr->description->special_type == SC_EXVALAR)) { /* print a header if this is the first council member */ if (councilfound == 0) { Do_send_line(c, "Council of the Wise:\n"); } /* print out the member */ sprintf(string_buffer, "%s Level: %.0lf\n", game_ptr->description->name, game_ptr->description->level); Do_send_line(c, &string_buffer); /* indicate that we've found another member */ councilfound++; } /* look at the next game */ game_ptr = game_ptr->next_game; } /* search for the two highest players */ first_ptr = NULL; second_ptr = NULL; game_ptr = c->realm->games; while (game_ptr != NULL) { /* if the player is in the game */ if (game_ptr->description != NULL) { /* see if the current game is higher level than the current */ if ((first_ptr == NULL || (game_ptr->description->level > first_ptr->description->level)) && (game_ptr->description->special_type < SC_STEWARD) && (game_ptr->description->wizard < 3)) { /* put the current game into first position */ second_ptr = first_ptr; first_ptr = game_ptr; } else if ((second_ptr == NULL || (game_ptr->description->level > second_ptr->description->level)) && (game_ptr->description->special_type < SC_STEWARD) && (game_ptr->description->wizard < 3)) { /* put the current game as the second */ second_ptr = game_ptr; } } /* point to the next game */ game_ptr = game_ptr->next_game; } /* print out the search results */ if (first_ptr != NULL) { if (second_ptr != NULL) { sprintf(string_buffer, "Highest commoners are: %s Level: %.0lf and %s Level: %.0lf\n", first_ptr->description->name, first_ptr->description->level, second_ptr->description->name, second_ptr->description->level); } else { sprintf(string_buffer, "Highest commoner is: %s Level:%.0lf\n", first_ptr->description->name, first_ptr->description->level); } Do_send_line(c, &string_buffer); } /* print last to die */ /* if ((fp = fopen(_PATH_LASTDEAD,"r")) != NULL && fgets(Databuf, SZ_DATABUF, fp) != NULL) { mvaddstr(19, 25, "The last character to die was:\n"); mvaddstr(20, 40 - strlen(Databuf) / 2,Databuf); fclose(fp); } */ Do_unlock_mutex(&c->realm->realm_lock); } /*************************************************************************** / FUNCTION NAME: Do_lowercase(char *dest, char *source); / / FUNCTION: Handles error messages / / AUTHOR: Brian Kelly, 1/1/01 / / ARGUMENTS: / int error - the error code to be returned / char *message - the error message to be printed / / RETURN VALUE: none / / DESCRIPTION: / Process arguments, initialize program, and loop forever processing / player input. / ****************************************************************************/ Do_lowercase(char *dest, char *source) { int len, i; len = strlen(source); for (i = 0; i< len; i++) { dest[i] = tolower(source[i]); } dest[len] = '\0'; return; } /*************************************************************************** / FUNCTION NAME: Do_create_password(char *string); / / FUNCTION: Handles error messages / / AUTHOR: Brian Kelly, 1/1/01 / / ARGUMENTS: / int error - the error code to be returned / char *message - the error message to be printed / / RETURN VALUE: none / / DESCRIPTION: / Process arguments, initialize program, and loop forever processing / player input. / ****************************************************************************/ Do_create_password(char *string) { int len, i, letter; /* choose a password length */ len = 5 * RND() + 8; /* pick a random character */ for (i = 0; i< len; i++) { letter = 50 + RND() * 55; /* skip over non characters and numbers plus "01IOilo" */ if (letter > 57) letter += 7; if (letter > 72) ++letter; if (letter > 78) ++letter; if (letter > 90) letter += 6; if (letter > 104) ++letter; if (letter > 107) ++letter; if (letter > 110) ++letter; string[i] = (char) letter; } string[len] = '\0'; return; } /*************************************************************************** / FUNCTION NAME: Do_move_close(double *x, double *y, float distance); / / FUNCTION: Handles error messages / / AUTHOR: Brian Kelly, 1/5/01 / / ARGUMENTS: / int error - the error code to be returned / char *message - the error message to be printed / / RETURN VALUE: none / / DESCRIPTION: / Process arguments, initialize program, and loop forever processing / player input. / ****************************************************************************/ Do_move_close(double *x, double *y, double maxDistance) { double angle, distance; angle = RND() * 2 * 3.14159; distance = RND() * maxDistance; if (distance < 1.0) { distance = 1.0; } /* add half a point because floor(-3.25) = -4 */ *x += floor(cos(angle) * distance + .5); *y += floor(sin(angle) * distance + .5); return; } /************************************************************************ / / FUNCTION NAME: Do_replace_repetition(char *theString) / / FUNCTION: do random stuff / / AUTHOR: Brian Kelly, 1/2/01 / / ARGUMENTS: none / / RETURN VALUE: none / / MODULES CALLED: collecttaxes(), floor(), wmove(), drandom(), infloat(), / waddstr(), mvprintw(), getanswer() / / GLOBAL INPUTS: Player, *stdscr, *Statptr / / GLOBAL OUTPUTS: Player / / DESCRIPTION: / Handle gurus, medics, etc. / *************************************************************************/ Do_replace_repetition(char *theString) { char previousChar, thisChar; char *writePtr, *readPtr; int count; if (theString[0] == '\0') { return; } writePtr = readPtr = &theString[0]; while (*readPtr == ' ') { ++readPtr; } count = 1; previousChar = tolower(*readPtr); *writePtr++ = *readPtr++; while (*readPtr != '\0') { thisChar = tolower(*readPtr); /* if this is the same character */ if (thisChar == previousChar) { ++count; /* see if this is the fourth character that's the same */ if (count > 4) { /* skip over it */ readPtr++; continue; } } else if (thisChar != ' ') { previousChar = thisChar; count = 1; } /* copy the character over */ *writePtr++ = *readPtr++; } /* add a null */ *writePtr = '\0'; } /*************************************************************************** / FUNCTION NAME: Do_direction(struct client_t *c, double *x, double *y, char *direction) / / FUNCTION: Derives the direction of a target coordinate from current location / / AUTHOR: Brian Kelly, 5/9/01 / / ARGUMENTS: / / / RETURN VALUE: none / / DESCRIPTION: / / ****************************************************************************/ Do_direction(struct client_t *c, double *x, double *y, char *direction) { double radians; /* if we're on the X coordinate, get radians manually */ if (*x - c->player.x == 0) { if (*y - c->player.y > 0) { radians = 1.5708; } else if (*y - c->player.y < 0) { radians = 4.7124; } else { strcat(direction, "down"); return; } } else { /* find the angle */ radians = atan((*y - c->player.y)/(*x - c->player.x)); /* add 180 degrees if on the other side of the plane */ if (*x - c->player.x < 0) { radians += 3.1416; } } /* run around the circle */ if (radians > 4.3197) { strcat(direction, "south"); } else if (radians > 3.5343) { strcat(direction, "south-west"); } else if (radians > 2.7489) { strcat(direction, "west"); } else if (radians > 1.9635) { strcat(direction, "north-west"); } else if (radians > 1.1781) { strcat(direction, "north"); } else if (radians > .3927) { strcat(direction, "north-east"); } else if (radians > -.3927) { strcat(direction, "east"); } else if (radians > -1.1781) { strcat(direction, "south-east"); } else { strcat(direction, "south"); } return; } int Do_maxmove(struct client_t *c) { if ((c->player.circle > 19) && (c->player.circle < 36)) { return (int) MIN(ceil(c->player.level / 50.0) + 1.5, 10.0); } else { return (int) MIN(floor((c->player.level * 1.5) + 1.5), 100.0); } } int Do_anglemove(struct client_t *c) { return (int) MAX(1.0, floor(Do_maxmove(c) * .707106781)); }