Atrinik Server 2.5
commands/misc.c
Go to the documentation of this file.
00001 /************************************************************************
00002 *            Atrinik, a Multiplayer Online Role Playing Game            *
00003 *                                                                       *
00004 *    Copyright (C) 2009-2011 Alex Tokar and Atrinik Development Team    *
00005 *                                                                       *
00006 * Fork from Daimonin (Massive Multiplayer Online Role Playing Game)     *
00007 * and Crossfire (Multiplayer game for X-windows).                       *
00008 *                                                                       *
00009 * This program is free software; you can redistribute it and/or modify  *
00010 * it under the terms of the GNU General Public License as published by  *
00011 * the Free Software Foundation; either version 2 of the License, or     *
00012 * (at your option) any later version.                                   *
00013 *                                                                       *
00014 * This program is distributed in the hope that it will be useful,       *
00015 * but WITHOUT ANY WARRANTY; without even the implied warranty of        *
00016 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
00017 * GNU General Public License for more details.                          *
00018 *                                                                       *
00019 * You should have received a copy of the GNU General Public License     *
00020 * along with this program; if not, write to the Free Software           *
00021 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.             *
00022 *                                                                       *
00023 * The author can be reached at admin@atrinik.org                        *
00024 ************************************************************************/
00025 
00031 #include <global.h>
00032 
00036 void maps_info(object *op)
00037 {
00038     mapstruct *m;
00039     char map_path[MAX_BUF];
00040     long sec = seconds();
00041 
00042     new_draw_info_format(0, COLOR_WHITE, op, "Current time is: %02ld:%02ld:%02ld.", (sec % 86400) / 3600, (sec % 3600) / 60, sec % 60);
00043     new_draw_info(0, COLOR_WHITE, op, "Path               Pl PlM IM   TO Dif Reset");
00044 
00045     for (m = first_map; m != NULL; m = m->next)
00046     {
00047         /* Print out the last 18 characters of the map name... */
00048         if (strlen(m->path) <= 18)
00049         {
00050             strcpy(map_path, m->path);
00051         }
00052         else
00053         {
00054             strcpy(map_path, m->path + strlen(m->path) - 18);
00055         }
00056 
00057         new_draw_info_format(0, COLOR_WHITE, op, "%-18.18s %2d   %c %4d %2d  %02d:%02d:%02d", map_path, players_on_map(m), m->in_memory ? (m->in_memory == MAP_IN_MEMORY ? 'm' : 's') : 'X', m->timeout, m->difficulty, (MAP_WHEN_RESET(m) % 86400) / 3600, (MAP_WHEN_RESET(m) % 3600) / 60, MAP_WHEN_RESET(m) % 60);
00058     }
00059 }
00060 
00066 int command_motd(object *op, char *params)
00067 {
00068     (void) params;
00069 
00070     display_motd(op);
00071     return 1;
00072 }
00073 
00077 static int count_active()
00078 {
00079     int i = 0;
00080     object *tmp = active_objects;
00081 
00082     while (tmp != NULL)
00083     {
00084         tmp = tmp->active_next, i++;
00085     }
00086 
00087     return i;
00088 }
00089 
00093 void malloc_info(object *op)
00094 {
00095     int players, nrofmaps;
00096     int nrm = 0, mapmem = 0, anr, anims, sum_alloc = 0, sum_used = 0, i, tlnr, alnr;
00097     treasurelist *tl;
00098     player *pl;
00099     mapstruct *m;
00100     archetype *at;
00101     artifactlist *al;
00102 
00103     for (tl = first_treasurelist, tlnr = 0; tl != NULL; tl = tl->next, tlnr++)
00104     {
00105     }
00106 
00107     for (al = first_artifactlist, alnr = 0; al != NULL; al = al->next, alnr++)
00108     {
00109     }
00110 
00111     for (at = first_archetype, anr = 0, anims = 0; at != NULL; at = at->more == NULL ? at->next : at->more, anr++)
00112     {
00113     }
00114 
00115     for (i = 1; i < num_animations; i++)
00116     {
00117         anims += animations[i].num_animations;
00118     }
00119 
00120     for (pl = first_player, players = 0; pl != NULL; pl = pl->next, players++)
00121     {
00122     }
00123 
00124     for (m = first_map, nrofmaps = 0; m != NULL; m = m->next, nrofmaps++)
00125     {
00126         if (m->in_memory == MAP_IN_MEMORY)
00127         {
00128             mapmem += MAP_WIDTH(m) * MAP_HEIGHT(m) * (sizeof(object *) + sizeof(MapSpace));
00129             nrm++;
00130         }
00131     }
00132 
00133     new_draw_info_format(0, COLOR_WHITE, op, "Sizeof: object=%ld  player=%ld  map=%ld", (long) sizeof(object), (long) sizeof(player), (long) sizeof(mapstruct));
00134 
00135     dump_mempool_statistics(op, &sum_used, &sum_alloc);
00136 
00137     new_draw_info_format(0, COLOR_WHITE, op, "%4d active objects", count_active());
00138 
00139     new_draw_info_format(0, COLOR_WHITE, op, "%4d maps allocated:  %8d", nrofmaps, i = (nrofmaps * sizeof(mapstruct)));
00140     sum_alloc += i;
00141     sum_used += nrm * sizeof(mapstruct);
00142 
00143     new_draw_info_format(0, COLOR_WHITE, op, "%4d maps in memory:  %8d", nrm, mapmem);
00144     sum_alloc += mapmem;
00145     sum_used += mapmem;
00146 
00147     new_draw_info_format(0, COLOR_WHITE, op, "%4d archetypes:      %8d", anr, i = (anr * sizeof(archetype)));
00148     sum_alloc += i;
00149     sum_used += i;
00150 
00151     new_draw_info_format(0, COLOR_WHITE, op, "%4d animations:      %8d", anims, i = (anims * sizeof(Fontindex)));
00152     sum_alloc += i;
00153     sum_used += i;
00154 
00155     new_draw_info_format(0, COLOR_WHITE, op, "%4d spells:          %8d", NROFREALSPELLS, i = (NROFREALSPELLS * sizeof(spell_struct)));
00156     sum_alloc += i;
00157     sum_used += i;
00158 
00159     new_draw_info_format(0, COLOR_WHITE, op, "%4d treasurelists    %8d", tlnr, i = (tlnr * sizeof(treasurelist)));
00160     sum_alloc += i;
00161     sum_used += i;
00162 
00163     new_draw_info_format(0, COLOR_WHITE, op, "%4ld treasures        %8d", nroftreasures, i = (nroftreasures * sizeof(treasure)));
00164     sum_alloc += i;
00165     sum_used += i;
00166 
00167     new_draw_info_format(0, COLOR_WHITE, op, "%4ld artifacts        %8d", nrofartifacts, i = (nrofartifacts * sizeof(artifact)));
00168     sum_alloc += i;
00169     sum_used += i;
00170 
00171     new_draw_info_format(0, COLOR_WHITE, op, "%4ld artifacts strngs %8d", nrofallowedstr, i = (nrofallowedstr * sizeof(linked_char)));
00172     sum_alloc += i;
00173     sum_used += i;
00174 
00175     new_draw_info_format(0, COLOR_WHITE, op, "%4d artifactlists    %8d", alnr, i = (alnr * sizeof(artifactlist)));
00176     sum_alloc += i;
00177     sum_used += i;
00178 
00179     new_draw_info_format(0, COLOR_WHITE, op, "Total space allocated:%8d", sum_alloc);
00180     new_draw_info_format(0, COLOR_WHITE, op, "Total space used:     %8d", sum_used);
00181 }
00182 
00186 static void current_map_info(object *op)
00187 {
00188     mapstruct *m = op->map;
00189     MapSpace *msp;
00190 
00191     if (!m)
00192     {
00193         return;
00194     }
00195 
00196     msp = GET_MAP_SPACE_PTR(m, op->x, op->y);
00197     new_draw_info_format(0, COLOR_WHITE, op, "%s (%s, %s, x: %d, y: %d)", msp->map_info && OBJECT_VALID(msp->map_info, msp->map_info_count) && msp->map_info->race ? msp->map_info->race : m->name, msp->map_info && OBJECT_VALID(msp->map_info, msp->map_info_count) && msp->map_info->slaying ? msp->map_info->slaying : (m->bg_music ? m->bg_music : "no_music"), m->path, op->x, op->y);
00198 
00199     if (QUERY_FLAG(op, FLAG_WIZ))
00200     {
00201         new_draw_info_format(0, COLOR_WHITE, op, "Players: %d difficulty: %d size: %dx%d start: %dx%d", players_on_map(m), MAP_DIFFICULTY(m), MAP_WIDTH(m), MAP_HEIGHT(m), MAP_ENTER_X(m), MAP_ENTER_Y(m));
00202     }
00203 
00204     if (m->msg)
00205     {
00206         new_draw_info(0, COLOR_WHITE, op, m->msg);
00207     }
00208 }
00209 
00218 int command_who(object *op, char *params)
00219 {
00220     player *pl;
00221     int ip = 0, il = 0, wiz;
00222     char buf[MAX_BUF], race[MAX_BUF];
00223 
00224     if (!op)
00225     {
00226         return 1;
00227     }
00228 
00229     new_draw_info(0, COLOR_WHITE, op, " ");
00230 
00231     wiz = QUERY_FLAG(op, FLAG_WIZ);
00232 
00233     (void) params;
00234 
00235     for (pl = first_player; pl; pl = pl->next)
00236     {
00237         if (pl->dm_stealth && !wiz)
00238         {
00239             continue;
00240         }
00241 
00242         if (!pl->ob->map)
00243         {
00244             il++;
00245             continue;
00246         }
00247 
00248         ip++;
00249 
00250         if (pl->state == ST_PLAYING)
00251         {
00252             if (wiz)
00253             {
00254                 snprintf(buf, sizeof(buf), "%s (%s) [%s] (#%d)", pl->ob->name, pl->socket.host, pl->ob->map->path, pl->ob->count);
00255             }
00256             else
00257             {
00258                 snprintf(buf, sizeof(buf), "%s the %s %s (lvl %d)", pl->ob->name, gender_noun[object_get_gender(pl->ob)], player_get_race_class(pl->ob, race, sizeof(race)), pl->ob->level);
00259 
00260                 if (QUERY_FLAG(pl->ob, FLAG_WIZ))
00261                 {
00262                     strncat(buf, " [WIZ]", sizeof(buf) - strlen(buf) - 1);
00263                 }
00264 
00265                 if (pl->afk)
00266                 {
00267                     strncat(buf, " [AFK]", sizeof(buf) - strlen(buf) - 1);
00268                 }
00269 
00270                 if (pl->socket.is_bot)
00271                 {
00272                     strncat(buf, " [BOT]", sizeof(buf) - strlen(buf) - 1);
00273                 }
00274 
00275                 if (pl->class_ob && pl->class_ob->title)
00276                 {
00277                     strncat(buf, " ", sizeof(buf) - strlen(buf) - 1);
00278                     strncat(buf, pl->class_ob->title, sizeof(buf) - strlen(buf) - 1);
00279                 }
00280             }
00281 
00282             new_draw_info(0, COLOR_WHITE, op, buf);
00283         }
00284     }
00285 
00286     new_draw_info_format(0, COLOR_WHITE, op, "There %s %d player%s online (%d in login).", ip + il > 1 ? "are" : "is", ip + il, ip + il > 1 ? "s" : "", il);
00287 
00288     return 1;
00289 }
00290 
00296 int command_mapinfo(object *op, char *params)
00297 {
00298     (void) params;
00299 
00300     current_map_info(op);
00301     return 1;
00302 }
00303 
00309 int command_time(object *op, char *params)
00310 {
00311     (void) params;
00312 
00313     time_info(op);
00314     return 1;
00315 }
00316 
00322 int command_hiscore(object *op, char *params)
00323 {
00324     int results = 0;
00325 
00326     if (params)
00327     {
00328         results = atoi(params);
00329 
00330         /* If it was a number, don't bother using params to search in /hiscore. */
00331         if (results != 0)
00332         {
00333             params = NULL;
00334         }
00335         else if (strlen(params) < PLAYER_NAME_MIN)
00336         {
00337             new_draw_info_format(0, COLOR_WHITE, op, "Your search term must be at least %d characters long.", PLAYER_NAME_MIN);
00338             return 1;
00339         }
00340     }
00341 
00342     /* Add some limits. */
00343     if (results <= 0)
00344     {
00345         results = 25;
00346     }
00347     else if (results > 50)
00348     {
00349         results = 50;
00350     }
00351 
00352     hiscore_display(op, results, params);
00353     return 1;
00354 }
00355 
00361 int command_version(object *op, char *params)
00362 {
00363     (void) params;
00364 
00365     version(op);
00366 
00367     return 1;
00368 }
00369 
00375 int command_praying(object *op, char *params)
00376 {
00377     (void) params;
00378 
00379     CONTR(op)->praying = 1;
00380     return 1;
00381 }
00382 
00387 int onoff_value(char *line)
00388 {
00389     int i;
00390 
00391     if (sscanf(line, "%d", &i))
00392     {
00393         return (i != 0);
00394     }
00395 
00396     switch (line[0])
00397     {
00398         case 'o':
00399             switch (line[1])
00400             {
00401                 /* on */
00402                 case 'n':
00403                     return 1;
00404 
00405                 /* o[ff] */
00406                 default:
00407                     return 0;
00408             }
00409 
00410         /* y[es] */
00411         case 'y':
00412         /* k[ylla] */
00413         case 'k':
00414         case 's':
00415         case 'd':
00416             return 1;
00417 
00418         /* n[o] */
00419         case 'n':
00420         /* e[i] */
00421         case 'e':
00422         case 'u':
00423         default:
00424             return 0;
00425     }
00426 }
00427 
00431 void receive_player_name(object *op)
00432 {
00433     adjust_player_name(CONTR(op)->write_buf + 1);
00434 
00435     if (!check_name(CONTR(op), CONTR(op)->write_buf + 1))
00436     {
00437         get_name(op);
00438         return;
00439     }
00440 
00441     FREE_AND_COPY_HASH(op->name, CONTR(op)->write_buf + 1);
00442 
00443     get_password(op);
00444 }
00445 
00449 void receive_player_password(object *op)
00450 {
00451     unsigned int pwd_len = strlen(CONTR(op)->write_buf + 1);
00452 
00453     if (pwd_len < PLAYER_PASSWORD_MIN || pwd_len > PLAYER_PASSWORD_MAX)
00454     {
00455         send_socket_message(COLOR_RED, &CONTR(op)->socket, "That password has an invalid length.");
00456         get_name(op);
00457         return;
00458     }
00459 
00460     if (CONTR(op)->state == ST_CONFIRM_PASSWORD)
00461     {
00462         char cmd_buf[] = "X";
00463 
00464         if (!check_password(CONTR(op)->write_buf + 1, CONTR(op)->password))
00465         {
00466             send_socket_message(COLOR_RED, &CONTR(op)->socket, "The passwords did not match.");
00467             get_name(op);
00468             return;
00469         }
00470 
00471         Write_String_To_Socket(&CONTR(op)->socket, BINARY_CMD_NEW_CHAR, cmd_buf, 1);
00472         LOG(llevInfo, "NewChar send for %s\n", op->name);
00473         CONTR(op)->state = ST_ROLL_STAT;
00474 
00475         return;
00476     }
00477 
00478     strcpy(CONTR(op)->password, crypt_string(CONTR(op)->write_buf + 1, NULL));
00479     CONTR(op)->state = ST_ROLL_STAT;
00480     check_login(op);
00481     return;
00482 }
00483 
00491 int command_save(object *op, char *params)
00492 {
00493     (void) params;
00494 
00495     if (MAP_PLAYER_NO_SAVE(op->map))
00496     {
00497         new_draw_info(0, COLOR_WHITE, op, "You cannot save here.");
00498     }
00499     else if (save_player(op, 1))
00500     {
00501         new_draw_info(0, COLOR_WHITE, op, "You have been saved.");
00502     }
00503     else
00504     {
00505         new_draw_info(0, COLOR_WHITE, op, "SAVE FAILED!");
00506     }
00507 
00508     return 1;
00509 }
00510 
00516 int command_afk(object *op, char *params)
00517 {
00518     (void) params;
00519 
00520     if (CONTR(op)->afk)
00521     {
00522         CONTR(op)->afk = 0;
00523         new_draw_info(0, COLOR_WHITE, op, "You are no longer AFK.");
00524     }
00525     else
00526     {
00527         CONTR(op)->afk = 1;
00528         CONTR(op)->stat_afk_used++;
00529         new_draw_info(0, COLOR_WHITE, op, "You are now AFK.");
00530     }
00531 
00532     CONTR(op)->socket.ext_title_flag = 1;
00533 
00534     return 1;
00535 }
00536 
00542 int command_gsay(object *op, char *params)
00543 {
00544     char party_params[MAX_BUF];
00545 
00546     params = cleanup_chat_string(params);
00547 
00548     if (!params || *params == '\0')
00549     {
00550         return 0;
00551     }
00552 
00553     strcpy(party_params, "say ");
00554     strcat(party_params, params);
00555     command_party(op, party_params);
00556     return 0;
00557 }
00558 
00565 int command_party(object *op, char *params)
00566 {
00567     char buf[MAX_BUF];
00568 
00569     if (!params)
00570     {
00571         if (!CONTR(op)->party)
00572         {
00573             new_draw_info(0, COLOR_WHITE, op, "You are not a member of any party.");
00574             new_draw_info(0, COLOR_WHITE, op, "For help try: /party help");
00575         }
00576         else
00577         {
00578             new_draw_info_format(0, COLOR_WHITE, op, "You are a member of party %s (leader: %s).", CONTR(op)->party->name, CONTR(op)->party->leader);
00579         }
00580 
00581         return 1;
00582     }
00583 
00584     if (!strcmp(params, "help"))
00585     {
00586         new_draw_info(0, COLOR_WHITE, op, "To form a party type: /party form <partyname>");
00587         new_draw_info(0, COLOR_WHITE, op, "To join a party type: /party join <partyname>");
00588         new_draw_info(0, COLOR_WHITE, op, "If the party has a password, it will prompt you for it.");
00589         new_draw_info(0, COLOR_WHITE, op, "For a list of current parties type: /party list");
00590         new_draw_info(0, COLOR_WHITE, op, "To leave a party type: /party leave");
00591         new_draw_info(0, COLOR_WHITE, op, "To change a password for a party type: /party password <password>");
00592         new_draw_info(0, COLOR_WHITE, op, "There is a 8 character max for password.");
00593         new_draw_info(0, COLOR_WHITE, op, "To talk to party members type: /party say <msg> or /gsay <msg>");
00594         new_draw_info(0, COLOR_WHITE, op, "To see who is in your party: /party who");
00595         new_draw_info(0, COLOR_WHITE, op, "To change the party's looting mode: /party loot mode");
00596         new_draw_info(0, COLOR_WHITE, op, "To kick another player from your party: /party kick <name>");
00597         new_draw_info(0, COLOR_WHITE, op, "To change party leader: /party leader <name>");
00598         return 1;
00599     }
00600     else if (!strncmp(params, "say ", 4))
00601     {
00602         if (!CONTR(op)->party)
00603         {
00604             new_draw_info(0, COLOR_WHITE, op, "You are not a member of any party.");
00605             return 1;
00606         }
00607 
00608         params += 4;
00609         params = cleanup_chat_string(params);
00610 
00611         if (!params || *params == '\0')
00612         {
00613             return 1;
00614         }
00615 
00616         snprintf(buf, sizeof(buf), "[%s] %s says: %s", CONTR(op)->party->name, op->name, params);
00617         send_party_message(CONTR(op)->party, buf, PARTY_MESSAGE_CHAT, NULL);
00618         LOG(llevChat, "Party: %s [%s]: %s\n", op->name, CONTR(op)->party->name, params);
00619         return 1;
00620     }
00621     else if (!strcmp(params, "leave"))
00622     {
00623         if (!CONTR(op)->party)
00624         {
00625             new_draw_info(0, COLOR_WHITE, op, "You are not a member of any party.");
00626             return 1;
00627         }
00628 
00629         new_draw_info_format(0, COLOR_WHITE, op, "You leave party %s.", CONTR(op)->party->name);
00630         snprintf(buf, sizeof(buf), "%s leaves party %s.", op->name, CONTR(op)->party->name);
00631         send_party_message(CONTR(op)->party, buf, PARTY_MESSAGE_STATUS, op);
00632 
00633         remove_party_member(CONTR(op)->party, op);
00634         return 1;
00635     }
00636     else if (!strncmp(params, "password ", 9))
00637     {
00638         if (!CONTR(op)->party)
00639         {
00640             new_draw_info(0, COLOR_RED, op, "You are not a member of any party.");
00641             return 1;
00642         }
00643 
00644         if (CONTR(op)->party->leader != op->name)
00645         {
00646             new_draw_info(0, COLOR_RED, op, "Only the party's leader can change the password.");
00647             return 1;
00648         }
00649 
00650         strncpy(CONTR(op)->party->passwd, params + 9, sizeof(CONTR(op)->party->passwd) - 1);
00651         snprintf(buf, sizeof(buf), "The password for party %s changed to '%s'.", CONTR(op)->party->name, CONTR(op)->party->passwd);
00652         send_party_message(CONTR(op)->party, buf, PARTY_MESSAGE_STATUS, NULL);
00653         return 1;
00654     }
00655     else if (!strncmp(params, "form ", 5))
00656     {
00657         params = cleanup_chat_string(params + 5);
00658 
00659         if (!params || *params == '\0')
00660         {
00661             new_draw_info(0, COLOR_RED, op, "Invalid party name to form.");
00662             return 1;
00663         }
00664 
00665         if (CONTR(op)->party)
00666         {
00667             new_draw_info(0, COLOR_RED, op, "You must leave your current party before forming a new one.");
00668             return 1;
00669         }
00670 
00671         if (find_party(params))
00672         {
00673             new_draw_info_format(0, COLOR_WHITE, op, "The party %s already exists, pick another name.", params);
00674             return 1;
00675         }
00676 
00677         form_party(op, params);
00678         return 1;
00679     }
00680     else if (!strncmp(params, "loot", 4))
00681     {
00682         size_t i;
00683 
00684         params += 4;
00685 
00686         if (!CONTR(op)->party)
00687         {
00688             new_draw_info(0, COLOR_RED, op, "You are not a member of any party.");
00689             return 1;
00690         }
00691 
00692         if (!params || !*params || !++params)
00693         {
00694             new_draw_info_format(0, COLOR_WHITE, op, "Current looting mode: <green>%s</green>.", party_loot_modes[CONTR(op)->party->loot]);
00695             return 1;
00696         }
00697 
00698         if (CONTR(op)->party->leader != op->name)
00699         {
00700             new_draw_info(0, COLOR_RED, op, "Only the party's leader can change the looting mode.");
00701             return 1;
00702         }
00703 
00704         for (i = 0; i < PARTY_LOOT_MAX; i++)
00705         {
00706             if (!strcmp(params, party_loot_modes[i]))
00707             {
00708                 CONTR(op)->party->loot = i;
00709                 snprintf(buf, sizeof(buf), "Party looting mode changed to '%s'.", party_loot_modes[i]);
00710                 send_party_message(CONTR(op)->party, buf, PARTY_MESSAGE_STATUS, NULL);
00711                 return 1;
00712             }
00713         }
00714 
00715         new_draw_info(0, COLOR_WHITE, op, "Invalid looting mode. Valid modes are:");
00716 
00717         for (i = 0; i < PARTY_LOOT_MAX; i++)
00718         {
00719             new_draw_info_format(0, COLOR_WHITE, op, "<green>%s</green>: %s.", party_loot_modes[i], party_loot_modes_help[i]);
00720         }
00721 
00722         return 1;
00723     }
00724     else if (!strncmp(params, "kick", 4))
00725     {
00726         objectlink *ol;
00727 
00728         if (!CONTR(op)->party)
00729         {
00730             new_draw_info(0, COLOR_RED, op, "You are not a member of any party.");
00731             return 1;
00732         }
00733 
00734         if (CONTR(op)->party->leader != op->name)
00735         {
00736             new_draw_info(0, COLOR_RED, op, "Only the party's leader can kick other members of the party.");
00737             return 1;
00738         }
00739 
00740         params = cleanup_chat_string(params + 4);
00741 
00742         if (!params || *params == '\0')
00743         {
00744             new_draw_info(0, COLOR_WHITE, op, "Whom do you want to kick from the party?");
00745             return 1;
00746         }
00747 
00748         if (!strncasecmp(op->name, params, MAX_NAME))
00749         {
00750             new_draw_info(0, COLOR_RED, op, "You cannot kick yourself.");
00751             return 1;
00752         }
00753 
00754         for (ol = CONTR(op)->party->members; ol; ol = ol->next)
00755         {
00756             if (!strncasecmp(ol->objlink.ob->name, params, MAX_NAME))
00757             {
00758                 remove_party_member(CONTR(op)->party, ol->objlink.ob);
00759                 snprintf(buf, sizeof(buf), "%s has been kicked from the party.", ol->objlink.ob->name);
00760                 send_party_message(CONTR(op)->party, buf, PARTY_MESSAGE_STATUS, NULL);
00761                 new_draw_info_format(0, COLOR_RED, ol->objlink.ob, "You have been kicked from the party '%s'.", CONTR(op)->party->name);
00762                 return 1;
00763             }
00764         }
00765 
00766         new_draw_info(0, COLOR_RED, op, "There's no player with that name in your party.");
00767         return 1;
00768     }
00769     else if (!strncmp(params, "leader ", 7))
00770     {
00771         player *pl;
00772 
00773         if (!CONTR(op)->party)
00774         {
00775             new_draw_info(0, COLOR_RED, op, "You are not a member of any party.");
00776             return 1;
00777         }
00778 
00779         if (CONTR(op)->party->leader != op->name)
00780         {
00781             new_draw_info(0, COLOR_RED, op, "Only the party's leader can change the leader.");
00782             return 1;
00783         }
00784 
00785         pl = find_player(params + 7);
00786 
00787         if (!pl)
00788         {
00789             new_draw_info(0, COLOR_RED, op, "No such player.");
00790             return 1;
00791         }
00792 
00793         if (pl->ob == op)
00794         {
00795             new_draw_info(0, COLOR_RED, op, "You are already the party leader.");
00796             return 1;
00797         }
00798 
00799         if (!pl->party || pl->party != CONTR(op)->party)
00800         {
00801             new_draw_info(0, COLOR_RED, op, "That player is not a member of your party.");
00802             return 1;
00803         }
00804 
00805         FREE_AND_ADD_REF_HASH(pl->party->leader, pl->ob->name);
00806         new_draw_info_format(0, COLOR_WHITE, pl->ob, "You are the new leader of party %s!", pl->party->name);
00807         new_draw_info_format(0, COLOR_GREEN, op, "%s is the new leader of your party.", pl->ob->name);
00808         return 1;
00809     }
00810     else
00811     {
00812         party_struct *party;
00813         SockList sl;
00814         unsigned char sock_buf[MAXSOCKBUF];
00815 
00816         sl.buf = sock_buf;
00817         SOCKET_SET_BINARY_CMD(&sl, BINARY_CMD_PARTY);
00818 
00819         if (!strcmp(params, "list"))
00820         {
00821             SockList_AddChar(&sl, CMD_PARTY_LIST);
00822 
00823             for (party = first_party; party; party = party->next)
00824             {
00825                 SockList_AddString(&sl, party->name);
00826                 SockList_AddString(&sl, party->leader);
00827             }
00828         }
00829         else if (!strcmp(params, "who"))
00830         {
00831             objectlink *ol;
00832 
00833             if (!CONTR(op)->party)
00834             {
00835                 new_draw_info(0, COLOR_RED, op, "You are not a member of any party.");
00836                 return 1;
00837             }
00838 
00839             SockList_AddChar(&sl, CMD_PARTY_WHO);
00840 
00841             for (ol = CONTR(op)->party->members; ol; ol = ol->next)
00842             {
00843             if (CONTR(op)->socket.socket_version >= 1054)
00844             {
00845                 SockList_AddString(&sl, ol->objlink.ob->name);
00846                 SockList_AddChar(&sl, MAX(1, MIN((double) ol->objlink.ob->stats.hp / ol->objlink.ob->stats.maxhp * 100.0f, 100)));
00847                 SockList_AddChar(&sl, MAX(1, MIN((double) ol->objlink.ob->stats.sp / ol->objlink.ob->stats.maxsp * 100.0f, 100)));
00848                 SockList_AddChar(&sl, MAX(1, MIN((double) ol->objlink.ob->stats.grace / ol->objlink.ob->stats.maxgrace * 100.0f, 100)));
00849             }
00850             else
00851             {
00852                 SockList_AddString(&sl, ol->objlink.ob->name);
00853                 SockList_AddString(&sl, ol->objlink.ob->map->name);
00854                 SockList_AddChar(&sl, (char) ol->objlink.ob->level);
00855             }
00856             }
00857         }
00858         else if (!strncmp(params, "join ", 5))
00859         {
00860             char *party_name, *party_password;
00861 
00862             if (CONTR(op)->party)
00863             {
00864                 new_draw_info(0, COLOR_WHITE, op, "You must leave your current party before joining another.");
00865                 return 1;
00866             }
00867 
00868             params += 5;
00869 
00870             if (!params)
00871             {
00872                 return 1;
00873             }
00874 
00875             party_name = strtok(params, "\t");
00876             party_password = strtok(NULL, "\t");
00877 
00878             party = find_party(party_name);
00879 
00880             if (!party)
00881             {
00882                 new_draw_info(0, COLOR_WHITE, op, "No such party.");
00883                 return 1;
00884             }
00885 
00886             if (CONTR(op)->party != party)
00887             {
00888                 /* If party password is not set or they've typed correct password... */
00889                 if (party->passwd[0] == '\0' || (party_password && !strcmp(party->passwd, party_password)))
00890                 {
00891                     add_party_member(party, op);
00892                     CONTR(op)->stat_joined_party++;
00893                     new_draw_info_format(0, COLOR_GREEN, op, "You have joined party: %s.", party->name);
00894                     snprintf(buf, sizeof(buf), "%s joined party %s.", op->name, party->name);
00895                     send_party_message(party, buf, PARTY_MESSAGE_STATUS, op);
00896                     return 1;
00897                 }
00898                 /* Party password was typed but it wasn't correct. */
00899                 else if (party_password)
00900                 {
00901                     new_draw_info(0, COLOR_RED, op, "Incorrect party password.");
00902                     return 1;
00903                 }
00904                 /* Otherwise ask them to type the password */
00905                 else
00906                 {
00907                     new_draw_info(0, COLOR_YELLOW, op, "That party requires a password. Type it now, or press ESC to cancel joining.");
00908                     SockList_AddChar(&sl, CMD_PARTY_PASSWORD);
00909                     SockList_AddString(&sl, party->name);
00910                 }
00911             }
00912         }
00913 
00914         if (sl.len > 1)
00915         {
00916             Send_With_Handling(&CONTR(op)->socket, &sl);
00917         }
00918     }
00919 
00920     return 1;
00921 }
00922 
00929 int command_whereami(object *op, char *params)
00930 {
00931     if (!op->map->region)
00932     {
00933         new_draw_info(0, COLOR_WHITE, op, "You appear to be lost somewhere...");
00934         return 1;
00935     }
00936 
00937     (void) params;
00938 
00939     new_draw_info_format(0, COLOR_WHITE, op, "You are in %s.\n%s", get_region_longname(op->map->region), get_region_msg(op->map->region));
00940     return 1;
00941 }
00942 
00948 int command_ms_privacy(object *op, char *params)
00949 {
00950     if (CONTR(op)->ms_privacy)
00951     {
00952         CONTR(op)->ms_privacy = 0;
00953         new_draw_info(0, COLOR_WHITE, op, "Metaserver privacy turned off.");
00954     }
00955     else
00956     {
00957         CONTR(op)->ms_privacy = 1;
00958         new_draw_info(0, COLOR_WHITE, op, "Metaserver privacy turned on.");
00959     }
00960 
00961     (void) params;
00962     return 1;
00963 }
00964 
00970 int command_statistics(object *op, char *params)
00971 {
00972     size_t i;
00973 
00974     (void) params;
00975 
00976     new_draw_info_format(0, COLOR_WHITE, op, "Experience: %s", format_number_comma(op->stats.exp));
00977 
00978     if (op->level < MAXLEVEL)
00979     {
00980         char *cp = strdup_local(format_number_comma(level_exp(op->level + 1, 1.0)));
00981 
00982         new_draw_info_format(0, COLOR_WHITE, op, "Next Level:  %s (%s)", cp, format_number_comma(level_exp(op->level + 1, 1.0) - op->stats.exp));
00983         free(cp);
00984     }
00985 
00986     new_draw_info(0, COLOR_WHITE, op, "\nStat: Natural (Real)");
00987 
00988     for (i = 0; i < NUM_STATS; i++)
00989     {
00990         new_draw_info_format(0, COLOR_WHITE, op, "<green>%s:</green> %d (%d)", short_stat_name[i], get_attr_value(&CONTR(op)->orig_stats, i), get_attr_value(&op->stats, i));
00991     }
00992 
00993     new_draw_info_format(0, COLOR_WHITE, op, "\nYour equipped item power is %d out of %d.", CONTR(op)->item_power, op->level);
00994 
00995     return 1;
00996 }
00997 
01005 int command_region_map(object *op, char *params)
01006 {
01007     region *r;
01008     SockList sl;
01009     uint8 sock_buf[HUGE_BUF], params_check;
01010 
01011     if (!op->map)
01012     {
01013         return 1;
01014     }
01015 
01016     /* Server has not configured client maps URL. */
01017     if (settings.client_maps_url[0] == '\0')
01018     {
01019         new_draw_info(0, COLOR_WHITE, op, "This server does not support that command.");
01020         return 1;
01021     }
01022 
01023     /* Check if params were given and whether the player is allowed to
01024      * see map of any region they want. */
01025     params_check = params && can_do_wiz_command(CONTR(op), "region_map");
01026 
01027     if (params_check)
01028     {
01029         /* Search for the region the player wants. */
01030         for (r = first_region; r; r = r->next)
01031         {
01032             if (!strcasecmp(r->name, params))
01033             {
01034                 break;
01035             }
01036         }
01037 
01038         /* Not found, try partial region names. */
01039         if (!r)
01040         {
01041             size_t params_len = strlen(params);
01042 
01043             for (r = first_region; r; r = r->next)
01044             {
01045                 if (!strncasecmp(r->name, params, params_len))
01046                 {
01047                     break;
01048                 }
01049             }
01050         }
01051 
01052         if (!r)
01053         {
01054             new_draw_info(0, COLOR_WHITE, op, "No such region.");
01055             return 1;
01056         }
01057     }
01058     else
01059     {
01060         r = op->map->region;
01061     }
01062 
01063     /* Try to find a region that should have had a client map
01064      * generated. */
01065     for (; r; r = r->parent)
01066     {
01067         if (r->map_first)
01068         {
01069             break;
01070         }
01071     }
01072 
01073     if (!r)
01074     {
01075         if (params_check)
01076         {
01077             new_draw_info(0, COLOR_WHITE, op, "That region doesn't have a map.");
01078         }
01079         else
01080         {
01081             new_draw_info(0, COLOR_WHITE, op, "You cannot use that command here.");
01082         }
01083 
01084         return 1;
01085     }
01086 
01087     sl.buf = sock_buf;
01088     SOCKET_SET_BINARY_CMD(&sl, BINARY_CMD_REGION_MAP);
01089     SockList_AddString(&sl, op->map->path);
01090     SockList_AddShort(&sl, op->x);
01091     SockList_AddShort(&sl, op->y);
01092     SockList_AddString(&sl, r->name);
01093     SockList_AddString(&sl, settings.client_maps_url);
01094     Send_With_Handling(&CONTR(op)->socket, &sl);
01095 
01096     return 1;
01097 }