src/hcode/btech/mech.maps.c

Go to the documentation of this file.
00001 /*
00002  * Author: Markus Stenberg <fingon@iki.fi>
00003  *
00004  *  Copyright (c) 1996 Markus Stenberg
00005  *  Copyright (c) 1998-2002 Thomas Wouters
00006  *  Copyright (c) 2000-2002 Cord Awtry
00007  *  Copyright (c) 1999-2005 Kevin Stevens
00008  *       All rights reserved
00009  */
00010 
00011 #include "config.h"
00012 
00013 #include <stdio.h>
00014 #include <stdlib.h>
00015 #include <math.h>
00016 #include <sys/file.h>
00017 
00018 #include "mech.h"
00019 #include "create.h"
00020 #include "mech.events.h"
00021 #include "map.los.h"
00022 #include "p.mech.utils.h"
00023 #include "p.mech.los.h"
00024 #include "p.eject.h"
00025 #include "p.mech.restrict.h"
00026 #include "p.mech.maps.h"
00027 #include "p.mech.notify.h"
00028 #include "p.ds.bay.h"
00029 #include "p.bsuit.h"
00030 #include "p.mech.utils.h"
00031 #include "autopilot.h"
00032 
00033 void mech_findcenter(dbref player, void *data, char *buffer)
00034 {
00035         MECH *mech = (MECH *) data;
00036         float fx, fy;
00037         int x, y;
00038 
00039         cch(MECH_USUAL);
00040         x = MechX(mech);
00041         y = MechY(mech);
00042         MapCoordToRealCoord(x, y, &fx, &fy);
00043         notify_printf(player, "Current hex: (%d,%d,%d)\tRange to center: %.2f\t"
00044                                   "Bearing to center: %d", x, y, MechZ(mech),
00045                                   FindHexRange(fx, fy, MechFX(mech), MechFY(mech)),
00046                                   FindBearing(MechFX(mech), MechFY(mech), fx, fy));
00047 }
00048 
00049 static int parse_tacargs(dbref player, MECH * mech, char **args, int argc,
00050                                                  int maxrange, short *x, short *y)
00051 {
00052         int bearing;
00053         float range, fx, fy;
00054         MECH *tempMech;
00055         MAP *map;
00056 
00057         switch (argc) {
00058         case 2:
00059                 bearing = atoi(args[0]);
00060                 range = atof(args[1]);
00061                 DOCHECK0(!MechIsObservator(mech) &&
00062                                  abs((int) range) > maxrange,
00063                                  "Those coordinates are out of sensor range!");
00064                 FindXY(MechFX(mech), MechFY(mech), bearing, range, &fx, &fy);
00065                 RealCoordToMapCoord(x, y, fx, fy);
00066                 return 1;
00067         case 1:
00068                 map = getMap(mech->mapindex);
00069                 tempMech = getMech(FindMechOnMap(map, args[0]));
00070                 DOCHECK0(!tempMech, "No such target.");
00071                 range = FlMechRange(mech_map, mech, tempMech);
00072                 DOCHECK0(!InLineOfSight(mech, tempMech, MechX(tempMech),
00073                                                                 MechY(tempMech), range), "No such target.");
00074                 DOCHECK0(abs((int) range) > maxrange,
00075                                  "Target is out of scanner range.");
00076                 *x = MechX(tempMech);
00077                 *y = MechY(tempMech);
00078                 return 1;
00079         case 0:
00080                 *x = MechX(mech);
00081                 *y = MechY(mech);
00082                 return 1;
00083         default:
00084                 notify(player, "Invalid number of parameters!");
00085                 return 0;
00086         }
00087 }
00088 
00089 const char *GetTerrainName_base(int t)
00090 {
00091         switch (t) {
00092         case GRASSLAND:
00093         case '_':
00094                 return "Grassland";
00095         case HEAVY_FOREST:
00096                 return "Heavy Forest";
00097         case LIGHT_FOREST:
00098                 return "Light Forest";
00099         case ICE:
00100                 return "Ice";
00101         case BRIDGE:
00102                 return "Bridge";
00103         case HIGHWATER:
00104         case WATER:
00105                 return "Water";
00106         case ROUGH:
00107                 return "Rough";
00108         case MOUNTAINS:
00109                 return "Mountains";
00110         case ROAD:
00111                 return "Road";
00112         case BUILDING:
00113                 return "Building";
00114         case FIRE:
00115                 return "Fire";
00116         case SMOKE:
00117                 return "Smoke";
00118         case WALL:
00119                 return "Wall";
00120         }
00121         return "Unknown";
00122 }
00123 
00124 const char *GetTerrainName(MAP * map, int x, int y)
00125 {
00126         return GetTerrainName_base(GetTerrain(map, x, y));
00127 }
00128 
00129 /* Player-customizable colors */
00130 
00131 enum { SWATER_IDX, DWATER_IDX, BUILDING_IDX, ROAD_IDX, ROUGH_IDX,
00132                 MOUNTAIN_IDX,
00133         FIRE_IDX, ICE_IDX, WALL_IDX, SNOW_IDX, SMOKE_IDX, LWOOD_IDX, HWOOD_IDX,
00134         UNKNOWN_IDX, CLIFF_IDX, SELF_IDX, FRIEND_IDX, ENEMY_IDX, DS_IDX,
00135         GOODLZ_IDX, BADLZ_IDX, NUM_COLOR_IDX
00136 };
00137 
00138 /* Default colour string is "BbWnYyRWWWXGgbRHYRn" */
00139 /* internal rep has H instead of h and \0 instead of n */
00140 
00141 #define DEFAULT_COLOR_STRING "BbWXYyRWWWXGgbRhYRnGR"
00142 #define DEFAULT_COLOR_SCHEME "BbWXYyRWWWXGgbRHYR\0GR"
00143 
00144 static char custom_color_str[NUM_COLOR_IDX + 1] = DEFAULT_COLOR_SCHEME;
00145 
00146 static void set_colorscheme(dbref player)
00147 {
00148         char *str = silly_atr_get(player, A_MAPCOLOR);
00149         int i;
00150 
00151         if(*str && strlen(str) <= NUM_COLOR_IDX) {
00152                 strncpy(custom_color_str, DEFAULT_COLOR_STRING, NUM_COLOR_IDX);
00153                 strncpy(custom_color_str, str, strlen(str));
00154                 for(i = 0; i < NUM_COLOR_IDX; i++) {
00155                         switch (custom_color_str[i]) {
00156                         case 'f':
00157                         case 'F':
00158                         case 'I':
00159                         case 'i':
00160                         case 'H':
00161                         case 'x':
00162                         case 'X':
00163                         case 'r':
00164                         case 'R':
00165                         case 'g':
00166                         case 'G':
00167                         case 'y':
00168                         case 'Y':
00169                         case 'b':
00170                         case 'B':
00171                         case 'm':
00172                         case 'M':
00173                         case 'c':
00174                         case 'C':
00175                         case 'w':
00176                         case 'W':
00177                                 break;
00178                         case 'h':
00179                                 custom_color_str[i] = 'H';
00180                                 break;
00181                         case 'n':
00182                                 custom_color_str[i] = '\0';
00183                                 break;
00184                         default:
00185                                 notify_printf(player, "Invalid character '%c' in MAPCOLOR "
00186                                                           "attribute!", custom_color_str[i]);
00187                                 notify(player, "Using default: " DEFAULT_COLOR_STRING);
00188                                 memcpy(custom_color_str, DEFAULT_COLOR_SCHEME, NUM_COLOR_IDX);
00189                                 return;
00190                         }
00191                 }
00192                 return;
00193         } else if(*str) {
00194                 notify(player, "Invalid MAPCOLOR attribute!");
00195                 notify(player, "Using default: " DEFAULT_COLOR_STRING);
00196         }
00197         memcpy(custom_color_str, DEFAULT_COLOR_SCHEME, NUM_COLOR_IDX);
00198 }
00199 
00200 void mech_navigate(dbref player, void *data, char *buffer)
00201 {
00202         MECH *mech = (MECH *) data;
00203         char mybuff[NAVIGATE_LINES][MBUF_SIZE];
00204         MAP *mech_map;
00205         char **maptext, *args[3];
00206         int i, dolos, argc;
00207         short x, y;
00208 
00209         cch(MECH_USUAL);
00210 
00211         mech_map = getMap(mech->mapindex);
00212 
00213         dolos = MapIsDark(mech_map) || (MechType(mech) == CLASS_MW &&
00214                                                                         mudconf.btech_mw_losmap);
00215 
00216         DOCHECK(mech_map->map_width <= 0 || mech_map->map_height <= 0,
00217                         "Nothing to see on this map, move along.");
00218 
00219         argc = mech_parseattributes(buffer, args, 3);
00220         if(!parse_tacargs(player, mech, args, argc, MechTacRange(mech), &x, &y))
00221                 return;
00222 
00223         set_colorscheme(player);
00224         maptext = MakeMapText(player, mech, mech_map, x, y, 5, 5, 4, dolos);
00225 
00226         sprintf(mybuff[0],
00227                         "              0                                          %.150s",
00228                         maptext[0]);
00229         sprintf(mybuff[1],
00230                         "         ___________                                     %.150s",
00231                         maptext[1]);
00232         sprintf(mybuff[2],
00233                         "        /           \\          Location:%4d,%4d, %3d   %.150s",
00234                         MechX(mech), MechY(mech), MechZ(mech), maptext[2]);
00235         sprintf(mybuff[3],
00236                         "  300  /             \\  60     Terrain: %14s   %.150s",
00237                         GetTerrainName(mech_map, MechX(mech), MechY(mech)), maptext[3]);
00238         sprintf(mybuff[4],
00239                         "      /               \\                                  %.150s",
00240                         maptext[4]);
00241         sprintf(mybuff[5],
00242                         "     /                 \\                                 %.150s",
00243                         maptext[5]);
00244         sprintf(mybuff[6],
00245                         "270 (                   )  90  Speed:           %6.1f   %.150s",
00246                         MechSpeed(mech), maptext[6]);
00247         sprintf(mybuff[7],
00248                         "     \\                 /       Vertical Speed:  %6.1f   %.150s",
00249                         MechVerticalSpeed(mech), maptext[7]);
00250         sprintf(mybuff[8],
00251                         "      \\               /        Heading:           %4d   %.150s",
00252                         MechFacing(mech), maptext[8]);
00253         sprintf(mybuff[9],
00254                         "  240  \\             /  120                              %.150s",
00255                         maptext[9]);
00256         sprintf(mybuff[10],
00257                         "        \\___________/                                    %.150s",
00258                         maptext[10]);
00259         sprintf(mybuff[11], "                      ");
00260         sprintf(mybuff[12], "             180");
00261 
00262         navigate_sketch_mechs(mech, mech_map, x, y, mybuff);
00263         for(i = 0; i < NAVIGATE_LINES; i++)
00264                 notify(player, mybuff[i]);
00265 }
00266 
00267 /* INDENT OFF */
00268 
00269 /* 
00270    0
00271    ___________                                     /``\][/""\][/""\
00272    /           \          HEX Location: 254, 122    \`1/``\""/``\""/
00273    300  /             \  60     Terrain: Light Forest     /``\``/""\`3/""\
00274    /               \        Elevation:  0             \`2/``\"1/``\""/
00275    /                 \                                 /""\``|**\`3/""\
00276    270 (                   )  90  Speed: 0.0                \"4/``\"4/``\""/
00277    \                 /       Vertical Speed: 0.0       /""\`3/""\`3/""\
00278    \               /        Heading: 0                \"4/``\"4/``\""/
00279    240  \             /  120                              /""\`3/""\`3/""\
00280    \____*______/                                    \"4/][\"4/][\"4/
00281    180
00282    */
00283 
00284 /* INDENT ON */
00285 
00286 char GetLRSMechChar(MECH * mech, MECH * other)
00287 {
00288         char c = 'u';
00289 
00290         if(mech == other)
00291                 return '*';
00292         if(IsDS(other))
00293                 c = 'd';
00294         switch (MechMove(other)) {
00295         case MOVE_FLY:
00296                 c = 'a';
00297         case MOVE_BIPED:
00298                 c = 'b';
00299                 break;
00300         case MOVE_QUAD:
00301                 c = 'q';
00302                 break;
00303         case MOVE_TRACK:
00304                 c = 't';
00305                 break;
00306         case MOVE_WHEEL:
00307                 c = 'w';
00308                 break;
00309         case MOVE_HOVER:
00310                 c = 'h';
00311                 break;
00312         case MOVE_VTOL:
00313                 c = 'v';
00314                 break;
00315         case MOVE_HULL:
00316                 c = 'n';
00317                 break;
00318         case MOVE_SUB:
00319                 c = 's';
00320                 break;
00321         case MOVE_FOIL:
00322                 c = 'f';
00323                 break;
00324         }
00325         if(!MechSeemsFriend(mech, other))
00326                 c = toupper(c);
00327         return c;
00328 }
00329 
00330 static inline char TerrainColorChar(char terrain, int elev)
00331 {
00332         switch (terrain) {
00333         case HIGHWATER:
00334                 return custom_color_str[DWATER_IDX];
00335         case WATER:
00336                 if(elev < 2 || elev == '0' || elev == '1' || elev == '~')
00337                         return custom_color_str[SWATER_IDX];
00338                 return custom_color_str[DWATER_IDX];
00339         case BUILDING:
00340                 return custom_color_str[BUILDING_IDX];
00341         case ROAD:
00342                 return custom_color_str[ROAD_IDX];
00343         case ROUGH:
00344                 return custom_color_str[ROUGH_IDX];
00345         case MOUNTAINS:
00346                 return custom_color_str[MOUNTAIN_IDX];
00347         case FIRE:
00348                 return custom_color_str[FIRE_IDX];
00349         case ICE:
00350                 return custom_color_str[ICE_IDX];
00351         case WALL:
00352                 return custom_color_str[WALL_IDX];
00353         case SNOW:
00354                 return custom_color_str[SNOW_IDX];
00355         case SMOKE:
00356                 return custom_color_str[SMOKE_IDX];
00357         case LIGHT_FOREST:
00358                 return custom_color_str[LWOOD_IDX];
00359         case HEAVY_FOREST:
00360                 return custom_color_str[HWOOD_IDX];
00361         case UNKNOWN_TERRAIN:
00362                 return custom_color_str[UNKNOWN_IDX];
00363         }
00364         return '\0';
00365 }
00366 
00367 static char *add_color(char newc, char *prevc, char c)
00368 {
00369         static char buf[10];            /* won't be filled with more than 7 characters */
00370         buf[0] = '\0';
00371 
00372         if(newc == *prevc) {
00373                 buf[0] = c;
00374                 buf[1] = '\0';
00375                 return buf;
00376         }
00377 
00378         if(!newc || ((isupper(*prevc)) && !isupper(newc)) ||
00379            (newc == 'H' && *prevc))
00380                 strcpy(buf, "%cn");
00381         else if(isupper(newc) && !isupper(*prevc))
00382                 strcpy(buf, "%ch");
00383 
00384         if(!newc)
00385                 sprintf(buf + strlen(buf), "%c", c);
00386         else
00387                 sprintf(buf + strlen(buf), "%%c%c%c", tolower(newc), c);
00388         *prevc = newc;
00389         return buf;
00390 }
00391 
00392 static char *GetLRSMech(MECH * mech, MECH * other, int docolor, char *prevc)
00393 {
00394         static char buf[2];                     /* Won't be filled with more than 1 character */
00395         char c = GetLRSMechChar(mech, other);
00396         char newc;
00397 
00398         if(!docolor) {
00399                 sprintf(buf, "%c", c);
00400                 return buf;
00401         }
00402 
00403         if(mech == other)
00404                 newc = custom_color_str[SELF_IDX];
00405         else if(!MechSeemsFriend(mech, other))
00406                 newc = custom_color_str[ENEMY_IDX];
00407         else
00408                 newc = custom_color_str[FRIEND_IDX];
00409 
00410         return add_color(newc, prevc, c);
00411 
00412 }
00413 
00414 static char *LRSTerrain(MAP * map, int x, int y, int docolor, char *prevc)
00415 {
00416         static char buf[2];                     /* Won't be filled with more than 1 character */
00417 
00418         char c = GetTerrain(map, x, y);
00419         char newc;
00420 
00421         if(!c || !docolor || c == ' ') {
00422                 buf[0] = c;
00423                 buf[1] = '\0';
00424                 return buf;
00425         } else
00426                 newc = TerrainColorChar(c, GetElev(map, x, y));
00427 
00428         return add_color(newc, prevc, c);
00429 }
00430 
00431 static char *LRSElevation(MAP * map, int x, int y, int docolor, char *prevc)
00432 {
00433         static char buf[2];                     /* Won't be filled with more than 1 character */
00434 
00435         int e = GetElev(map, x, y);
00436         char c = (e || docolor) ? '0' + e : ' ';
00437         char newc;
00438 
00439         if(!docolor) {
00440                 buf[0] = c;
00441                 buf[1] = '\0';
00442                 return buf;
00443         } else
00444                 newc = TerrainColorChar(GetTerrain(map, x, y), e);
00445 
00446         return add_color(newc, prevc, c);
00447 }
00448 
00449 #define LRS_TERRAINMODE         1
00450 #define LRS_ELEVMODE            2
00451 #define LRS_MECHMODE            4
00452 #define LRS_LOSMODE             8
00453 #define LRS_COLORMODE           16
00454 #define LRS_ELEVCOLORMODE       32
00455 
00456 static char *get_lrshexstr(MECH * mech, MAP * map, int x, int y,
00457                                                    char *prevc, int mode, MECH ** mechs, int lm,
00458                                                    hexlosmap_info * losmap)
00459 {
00460         int losflag = MAPLOSHEX_SEE | MAPLOSHEX_SEEN;
00461 
00462         if(mode & LRS_MECHMODE) {
00463                 while (mechs[lm] && MechY(mechs[lm]) < y)
00464                         lm++;
00465                 while (mechs[lm] && MechY(mechs[lm]) == y && MechX(mechs[lm]) < x)
00466                         lm++;
00467                 if(mechs[lm] && MechY(mechs[lm]) == y && MechX(mechs[lm]) == x)
00468                         return GetLRSMech(mech, mechs[lm], mode & LRS_COLORMODE, prevc);
00469         }
00470 
00471         if(losmap)
00472                 losflag = LOSMap_GetFlag(losmap, x, y);
00473 
00474         /* If the losmap doesn't contain this hex, we return X in bold red
00475          * in both terrain and elevation mode.
00476          */
00477         if(!(losflag & MAPLOSHEX_SEEN))
00478                 return add_color('R', prevc, 'X');
00479 
00480         if(((mode & LRS_TERRAINMODE) && !(losflag & MAPLOSHEX_SEETERRAIN)) ||
00481            ((mode & LRS_ELEVMODE) && !(losflag & MAPLOSHEX_SEEELEV)))
00482                 return add_color(TerrainColorChar(UNKNOWN_TERRAIN, 0), prevc, '?');
00483 
00484         if(mode & LRS_ELEVMODE)
00485                 return LRSElevation(map, x, y, mode & LRS_ELEVCOLORMODE, prevc);
00486         if(mode & LRS_TERRAINMODE)
00487                 return LRSTerrain(map, x, y, mode & LRS_COLORMODE, prevc);
00488 
00489         SendError(tprintf("Unknown LRS mode, mech #%d mode 0x%x.",
00490                                           mech->mynum, mode));
00491         return add_color('R', prevc, 'Y');
00492 
00493 }
00494 
00495 static void show_lrs_map(dbref player, MECH * mech, MAP * map, int x,
00496                                                  int y, int displayHeight, int mode)
00497 {
00498         int loop, b_width, e_width, b_height, e_height, i;
00499         MECH *oMech;
00500 
00501         /* topbuff and botbuff must be capable of holding enough
00502          * characters to colorize all hexes in the most inefficient
00503          * way. This means 15 characters per 2 hexes, or 8 per
00504          * hex. topbuff and botbuff both hold half the hexes on the row,
00505          * so that ends up 4 * LRS_DISPLAY_WIDTH (plus some padding thrown
00506          * in for good measure.)
00507          *
00508          * midbuff is only used for the lables, and only needs a few
00509          * characters more than the display width.
00510          */
00511         char topbuff[4 * LRS_DISPLAY_WIDTH + 30] = "    ";
00512         char botbuff[4 * LRS_DISPLAY_WIDTH + 30] = "    ";
00513         char midbuff[8 + LRS_DISPLAY_WIDTH] = "    ";
00514         char trash1[5];                         /* temp var to hold the max-three-digit number of map Y */
00515         short oddcol = 0;
00516         MECH *mechs[MAX_MECHS_PER_MAP];
00517         int last_mech = 0;
00518         char prevct = 0, prevcb = 0;
00519         hexlosmap_info *losmap = NULL;
00520 
00521         /* x and y hold the viewing center of the map */
00522         b_width = x - LRS_DISPLAY_WIDTH / 2;
00523         b_width = MAX(b_width, 0);
00524         e_width = b_width + LRS_DISPLAY_WIDTH;
00525         if(e_width >= map->map_width) {
00526                 e_width = map->map_width - 1;
00527                 b_width = e_width - LRS_DISPLAY_WIDTH;
00528                 b_width = MAX(b_width, 0);
00529         }
00530 
00531         if(b_width % 2)
00532                 oddcol = 1;
00533 
00534         b_height = y - displayHeight / 2;
00535         b_height = MAX(b_height, 0);
00536         e_height = b_height + displayHeight;
00537         if(e_height > map->map_height) {
00538                 e_height = map->map_height;
00539                 b_height = e_height - displayHeight;
00540                 b_height = MAX(b_height, 0);
00541         }
00542 
00543         /* Display the top labels */
00544         for(i = b_width; i <= e_width; i++) {
00545                 sprintf(trash1, "%3d", i);
00546                 sprintf(topbuff + strlen(topbuff), "%c", trash1[0]);
00547                 sprintf(midbuff + strlen(midbuff), "%c", trash1[1]);
00548                 sprintf(botbuff + strlen(botbuff), "%c", trash1[2]);
00549         }
00550         notify(player, topbuff);
00551         notify(player, midbuff);
00552         notify(player, botbuff);
00553 
00554         if(mode & LRS_MECHMODE) {
00555                 for(i = 0; i < map->first_free; i++) {
00556                         if((oMech = getMech(map->mechsOnMap[i]))) {
00557                                 if((mech == oMech) ||
00558                                    (MechY(oMech) >= b_height && MechY(oMech) <= e_height &&
00559                                         MechX(oMech) >= b_width && MechX(oMech) <= e_width &&
00560                                         InLineOfSight(mech, oMech, MechX(oMech), MechY(oMech),
00561                                                                   FlMechRange(map, mech, oMech))))
00562                                         mechs[last_mech++] = oMech;
00563                         }
00564                 }
00565                 for(i = 0; i < (last_mech - 1); i++)    /* Bubble-sort the list 
00566                                                                                                  *  to y/x order */
00567                         for(loop = (i + 1); loop < last_mech; loop++) {
00568                                 if(MechY(mechs[i]) > MechY(mechs[loop])) {
00569                                         oMech = mechs[i];
00570                                         mechs[i] = mechs[loop];
00571                                         mechs[loop] = oMech;
00572                                 } else if(MechY(mechs[i]) == MechY(mechs[loop]) &&
00573                                                   MechX(mechs[i]) > MechX(mechs[loop])) {
00574                                         oMech = mechs[i];
00575                                         mechs[i] = mechs[loop];
00576                                         mechs[loop] = oMech;
00577                                 }
00578                         }
00579                 mechs[last_mech] = NULL;
00580                 last_mech = 0;
00581         }
00582 
00583         if(mode & LRS_LOSMODE)
00584                 losmap = CalculateLOSMap(map, mech, b_width, b_height,
00585                                                                  e_width - b_width, e_height - b_height);
00586 
00587         for(loop = b_height; loop < e_height; loop++) {
00588                 sprintf(topbuff, "%3d ", loop);
00589                 strcpy(botbuff, "    ");
00590                 if(mode & LRS_MECHMODE)
00591                         while (mechs[last_mech] && MechY(mechs[last_mech]) < loop)
00592                                 last_mech++;
00593 
00594                 for(i = b_width; i < e_width; i += 2) {
00595                         sprintf(topbuff + strlen(topbuff), oddcol ? "%s " : " %s",
00596                                         get_lrshexstr(mech, map, i + !oddcol, loop, &prevct,
00597                                                                   mode, mechs, last_mech, losmap));
00598 
00599                         sprintf(botbuff + strlen(botbuff), oddcol ? " %s" : "%s ",
00600                                         get_lrshexstr(mech, map, i + oddcol, loop, &prevcb,
00601                                                                   mode, mechs, last_mech, losmap));
00602                 }
00603                 if(i == e_width && !oddcol) {
00604                         sprintf(botbuff + strlen(botbuff), "%s",
00605                                         get_lrshexstr(mech, map, i, loop, &prevcb, mode,
00606                                                                   mechs, last_mech, losmap));
00607                 } else if(i == e_width) {
00608                         sprintf(topbuff + strlen(topbuff), "%s",
00609                                         get_lrshexstr(mech, map, i, loop, &prevct, mode,
00610                                                                   mechs, last_mech, losmap));
00611                         strcat(botbuff, " ");
00612                 }
00613 
00614                 if(mode & (LRS_COLORMODE | LRS_ELEVCOLORMODE)) {
00615                         if(prevct) {
00616                                 strcat(topbuff, "%cn");
00617                                 prevct = 0;
00618                         }
00619                         if(prevcb) {
00620                                 strcat(botbuff, "%cn");
00621                                 prevcb = 0;
00622                         }
00623                 }
00624                 sprintf(botbuff + strlen(botbuff), " %-3d", loop);
00625                 notify(player, topbuff);
00626                 notify(player, botbuff);
00627         }
00628 }
00629 
00630 void mech_lrsmap(dbref player, void *data, char *buffer)
00631 {
00632         MECH *mech = (MECH *) data;
00633         MAP *map;
00634         int argc, mode = 0;
00635         short x, y;
00636         char *args[5], *str;
00637         int displayHeight = LRS_DISPLAY_HEIGHT;
00638 
00639         cch(MECH_USUAL);
00640 
00641         if(Ansimap(player))
00642                 mode |= LRS_COLORMODE;
00643 
00644         map = getMap(mech->mapindex);
00645 
00646         argc = mech_parseattributes(buffer, args, 4);
00647         DOCHECK(!MechLRSRange(mech), "Your system seems to be inoperational.");
00648         if(!parse_tacargs(player, mech, &args[1], argc - 1,
00649                                           MechLRSRange(mech), &x, &y))
00650                 return;
00651         switch (args[0][0]) {
00652         case 'M':
00653         case 'm':
00654                 mode |= LRS_MECHMODE | LRS_TERRAINMODE;
00655                 break;
00656         case 'E':
00657         case 'e':
00658                 mode |= LRS_ELEVMODE;
00659                 break;
00660         case 'C':
00661         case 'c':
00662                 mode |= LRS_ELEVMODE | LRS_ELEVCOLORMODE;
00663                 break;
00664         case 'T':
00665         case 't':
00666                 mode |= LRS_TERRAINMODE;
00667                 break;
00668         case 'L':
00669         case 'l':
00670                 mode |= LRS_LOSMODE | LRS_TERRAINMODE;
00671                 break;
00672         case 'H':
00673         case 'h':
00674                 mode |= LRS_LOSMODE | LRS_ELEVMODE;
00675                 break;
00676         case 'S':
00677         case 's':
00678                 mode |= LRS_LOSMODE | LRS_MECHMODE | LRS_TERRAINMODE;
00679                 break;
00680         default:
00681                 notify_printf(player, "Unknown LRS sensor type '%s'!", args[0]);
00682                 return;
00683         }
00684 
00685         if(MapIsDark(map) || (MechType(mech) == CLASS_MW &&
00686                                                   mudconf.btech_mw_losmap))
00687                 mode |= LRS_LOSMODE;
00688 
00689         str = silly_atr_get(player, A_LRSHEIGHT);
00690         if(*str) {
00691                 displayHeight = atoi(str);
00692                 if(displayHeight < 10 || displayHeight > 40) {
00693                         notify(player,
00694                                    "Illegal LRSHeight attribute.  Must be between 10 and 40");
00695                         displayHeight = LRS_DISPLAY_HEIGHT;
00696                 }
00697         }
00698 
00699         displayHeight = MIN(displayHeight, 2 * MechLRSRange(mech));
00700         displayHeight = MIN(displayHeight, map->map_height);
00701 
00702         if(!(displayHeight % 2))
00703                 displayHeight++;
00704 
00705         set_colorscheme(player);
00706 
00707         show_lrs_map(player, mech, map, x, y, displayHeight, mode);
00708 }
00709 
00710 static inline int is_oddcol(int col)
00711 {
00712         /*
00713          * The only real trick here is to handle negative
00714          * numbers correctly.
00715          */
00716         return (unsigned) col & 1;
00717 }
00718 
00719 static inline int tac_dispcols(int hexcols)
00720 {
00721         return hexcols * 3 + 1;
00722 }
00723 
00724 static inline int tac_hex_offset(int x, int y, int dispcols, int oddcol1)
00725 {
00726         int oddcolx = is_oddcol(x + oddcol1);
00727 
00728         return (y * 2 + 1 - oddcolx) * dispcols + x * 3 + 1;
00729 }
00730 
00731 static inline void sketch_tac_row(char *pos, int left_offset,
00732                                                                   char const *src, int len)
00733 {
00734         memset(pos, ' ', left_offset);
00735         memcpy(pos + left_offset, src, len);
00736         pos[left_offset + len] = '\0';
00737 }
00738 
00739 static void sketch_tac_map(char *buf, MAP * map, MECH * mech, int sx,
00740                                                    int sy, int wx, int wy, int dispcols,
00741                                                    int top_offset, int left_offset, int docolour,
00742                                                    int dohexlos)
00743 {
00744 #if 0
00745         static char const hexrow[2][76] = {
00746                 "\\][/][\\][/][\\][/][\\][/][\\][/][\\][/][\\][/][\\][/][\\][/][\\][/][\\][/][\\][/][\\][/",
00747                 "/][\\][/][\\][/][\\][/][\\][/][\\][/][\\][/][\\][/][\\][/][\\][/][\\][/][\\][/][\\][/][\\"
00748         };
00749 #else
00750         static char const hexrow[2][310] = {
00751                 "\\][/][\\][/][\\][/][\\][/][\\][/][\\][/][\\][/][\\][/][\\][/][\\][/][\\][/]["
00752                         "\\][/][\\][/][\\][/][\\][/][\\][/][\\][/][\\][/][\\][/][\\][/][\\][/][\\][/]["
00753                         "\\][/][\\][/][\\][/][\\][/][\\][/][\\][/][\\][/][\\][/][\\][/][\\][/][\\][/]["
00754                         "\\][/][\\][/][\\][/][\\][/][\\][/][\\][/][\\][/][\\][/][\\][/][\\][/][\\][/]["
00755                         "\\][/][\\][/][\\][/][\\][/][\\][/][\\][/][\\][/][\\][/",
00756                 "/][\\][/][\\][/][\\][/][\\][/][\\][/][\\][/][\\][/][\\][/][\\][/][\\][/][\\]["
00757                         "/][\\][/][\\][/][\\][/][\\][/][\\][/][\\][/][\\][/][\\][/][\\][/][\\][/][\\]["
00758                         "/][\\][/][\\][/][\\][/][\\][/][\\][/][\\][/][\\][/][\\][/][\\][/][\\][/][\\]["
00759                         "/][\\][/][\\][/][\\][/][\\][/][\\][/][\\][/][\\][/][\\][/][\\][/][\\][/][\\]["
00760                         "/][\\][/][\\][/][\\][/][\\][/][\\][/][\\][/][\\][/][\\"
00761         };
00762 #endif
00763         int x, y;
00764         int oddcol1 = is_oddcol(sx);    /* One iff first hex col is odd */
00765         char *pos;
00766         int mapcols = tac_dispcols(wx);
00767         hexlosmap_info *losmap = NULL;
00768 
00769         /*
00770          * First create a blank hex map.
00771          */
00772         pos = buf;
00773         for(y = 0; y < top_offset; y++) {
00774                 memset(pos, ' ', dispcols - 1);
00775                 pos[dispcols - 1] = '\0';
00776                 pos += dispcols;
00777         }
00778         for(y = 0; y < wy; y++) {
00779                 sketch_tac_row(pos, left_offset, hexrow[oddcol1], mapcols);
00780                 pos += dispcols;
00781                 sketch_tac_row(pos, left_offset, hexrow[!oddcol1], mapcols);
00782                 pos += dispcols;
00783         }
00784         sketch_tac_row(pos, left_offset, hexrow[oddcol1], mapcols);
00785 
00786         /*
00787          * Now draw the terrain and elevation. 
00788          */
00789         pos = buf + top_offset * dispcols + left_offset;
00790         wx = MIN(wx, map->map_width - sx);
00791         wy = MIN(wy, map->map_height - sy);
00792 
00793         if(dohexlos)
00794                 losmap = CalculateLOSMap(map, mech, MAX(0, sx), MAX(0, sy), wx, wy);
00795 
00796         for(y = MAX(0, -sy); y < wy; y++) {
00797                 for(x = MAX(0, -sx); x < wx; x++) {
00798                         int terr, elev, losflag = MAPLOSHEX_SEE | MAPLOSHEX_SEEN;
00799                         char *base;
00800                         char topchar, botchar;
00801 
00802                         if(losmap)
00803                                 losflag = LOSMap_GetFlag(losmap, sx + x, sy + y);
00804 
00805                         if(!(losflag & MAPLOSHEX_SEEN)) {
00806                                 terr = 'X';
00807                                 elev = 40;              /* 'X' */
00808                         } else {
00809 
00810                                 if(losflag & MAPLOSHEX_SEETERRAIN)
00811                                         terr = GetTerrain(map, sx + x, sy + y);
00812                                 else
00813                                         terr = UNKNOWN_TERRAIN;
00814 
00815                                 if(losflag & MAPLOSHEX_SEEELEV)
00816                                         elev = GetElev(map, sx + x, sy + y);
00817                                 else
00818                                         elev = 15;      /* Ugly hack: '0' + 15 == '?' */
00819                         }
00820                         base = pos + tac_hex_offset(x, y, dispcols, oddcol1);
00821 
00822                         switch (terr) {
00823                         case WATER:
00824                                 /*
00825                                  * Colour hack:  Draw deep water with '\242'
00826                                  * if using colour so colourize_tac_map()
00827                                  * knows to use dark blue rather than light
00828                                  * blue
00829                                  */
00830                                 if(docolour && elev >= 2) {
00831                                         topchar = '\242';
00832                                         botchar = '\242';
00833                                 } else {
00834                                         topchar = '~';
00835                                         botchar = '~';
00836                                 }
00837                                 break;
00838 
00839                         case HIGHWATER:
00840                                 topchar = '~';
00841                                 botchar = '+';
00842                                 break;
00843 
00844                         case BRIDGE:
00845                                 topchar = '#';
00846                                 botchar = '+';
00847                                 break;
00848 
00849                         case ' ':                       /* GRASSLAND */
00850                                 topchar = ' ';
00851                                 botchar = '_';
00852                                 break;
00853 
00854                         case UNKNOWN_TERRAIN:
00855                                 topchar = '?';
00856                                 botchar = '?';
00857                                 break;
00858 
00859                         default:
00860                                 topchar = terr;
00861                                 botchar = terr;
00862                                 break;
00863                         }
00864 
00865                         base[0] = topchar;
00866                         base[1] = topchar;
00867                         base[dispcols + 0] = botchar;
00868                         if(elev > 0) {
00869                                 botchar = '0' + elev;
00870                         }
00871                         base[dispcols + 1] = botchar;
00872                 }
00873         }
00874 }
00875 
00876 /*
00877  * Draw one of the seven hexes that a Dropship takes up on a tac map.
00878  */
00879 static void sketch_tac_ds(char *base, int dispcols, char terr)
00880 {
00881         /*
00882          * Becareful not to overlay a 'mech id or terrain elevation.
00883          */
00884         if(!isalpha(base[0]) && base[0] != '*') {
00885                 base[0] = terr;
00886                 base[1] = terr;
00887         }
00888         base[dispcols + 0] = terr;
00889         if(!isdigit((unsigned char) base[dispcols + 1])) {
00890                 base[dispcols + 1] = terr;
00891         }
00892 }
00893 
00894 extern int dirs[6][2];
00895 
00896 static void sketch_tac_ownmech(char *buf, MAP * map, MECH * mech, int sx,
00897                                                            int sy, int wx, int wy, int dispcols,
00898                                                            int top_offset, int left_offset)
00899 {
00900 
00901         int oddcol1 = is_oddcol(sx);
00902         char *pos = buf + top_offset * dispcols + left_offset;
00903         char *base;
00904         int x = MechX(mech) - sx;
00905         int y = MechY(mech) - sy;
00906 
00907         if(x < 0 || x >= wx || y < 0 || y >= wy) {
00908                 return;
00909         }
00910         base = pos + tac_hex_offset(x, y, dispcols, oddcol1);
00911         base[0] = '*';
00912         base[0] = '*';
00913 }
00914 
00915 static void sketch_tac_mechs(char *buf, MAP * map, MECH * player_mech,
00916                                                          int sx, int sy, int wx, int wy, int dispcols,
00917                                                          int top_offset, int left_offset, int docolour,
00918                                                          int labels)
00919 {
00920         int i;
00921         char *pos = buf + top_offset * dispcols + left_offset;
00922         int oddcol1 = is_oddcol(sx);
00923 
00924         /*
00925          * Draw all the 'mechs on the map.
00926          */
00927         for(i = 0; i < map->first_free; i++) {
00928                 int x, y;
00929                 char *base;
00930                 MECH *mech;
00931 
00932                 if(map->mechsOnMap[i] == -1) {
00933                         continue;
00934                 }
00935 
00936                 mech = getMech(map->mechsOnMap[i]);
00937                 if(mech == NULL) {
00938                         continue;
00939                 }
00940 
00941                 /*
00942                  * Check to see if the 'mech is on the tac map and 
00943                  * that its in LOS of the player's 'mech.
00944                  */
00945                 x = MechX(mech) - sx;
00946                 y = MechY(mech) - sy;
00947                 if(!IsDS(mech) && (x < 0 || x >= wx || y < 0 || y >= wy)) {
00948                         continue;
00949                 }
00950 
00951                 if(IsDS(mech) && (x < -1 || x > wx || y < -1 || y > wy)) {
00952                         continue;
00953                 }
00954 
00955                 if(mech != player_mech &&
00956                    !InLineOfSight(player_mech, mech, MechX(mech), MechY(mech),
00957                                                   FlMechRange(map, player_mech, mech))) {
00958                         continue;
00959                 }
00960 
00961                 base = pos + tac_hex_offset(x, y, dispcols, oddcol1);
00962                 if(!(MechSpecials2(mech) & CARRIER_TECH) && IsDS(mech) &&
00963                    ((MechZ(mech) >= ORBIT_Z && mech != player_mech) || Landed(mech)
00964                         || !Started(mech))) {
00965                         int ts = DSBearMod(mech);
00966                         int dir;
00967 
00968                         /*
00969                          * Dropships are a special case.  They take up
00970                          * seven hexes on a tac map.  First draw the
00971                          * center hex and then the six surronding hexes.
00972                          */
00973 
00974                         for(dir = 0; dir < 6; dir++) {
00975                                 int tx = x + dirs[dir][0];
00976                                 int ty = y + dirs[dir][1];
00977 
00978                                 if((tx + oddcol1) % 2 == 0 && dirs[dir][0] != 0) {
00979                                         ty--;
00980                                 }
00981                                 if(tx < 0 || tx >= wx || ty < 0 || ty >= wy) {
00982                                         continue;
00983                                 }
00984                                 base = pos + tac_hex_offset(tx, ty, dispcols, oddcol1);
00985                                 if(Find_DS_Bay_Number(mech, (dir - ts + 6) % 6)
00986                                    >= 0) {
00987                                         sketch_tac_ds(base, dispcols, '@');
00988                                 } else {
00989                                         sketch_tac_ds(base, dispcols, '=');
00990                                 }
00991                         }
00992                         if(x < 0 || x >= wx || y < 0 || y >= wy)
00993                                 continue;
00994 
00995                         base = pos + tac_hex_offset(x, y, dispcols, oddcol1);
00996                         if(docolour) {
00997                                 /*
00998                                  * Colour hack: 'X' would be confused with
00999                                  * any enemy con by colourize_tac_map()
01000                                  */
01001                                 sketch_tac_ds(base, dispcols, '$');
01002                         } else {
01003                                 sketch_tac_ds(base, dispcols, 'X');
01004                         }
01005 
01006                         if(isalpha(base[0]))
01007                                 continue;
01008 
01009                         if(mech == player_mech) {
01010                                 base[0] = '*';
01011                                 base[1] = '*';
01012                         } else {
01013                                 char *id = MechIDS(mech, MechSeemsFriend(player_mech, mech));
01014                                 base[0] = id[0];
01015                                 base[1] = id[1];
01016                         }
01017 
01018                 } else if(mech == player_mech) {
01019                         if(isalpha(base[0]))
01020                                 continue;
01021                         base[0] = '*';
01022                         base[1] = '*';
01023                 } else {
01024                         char *id = MechIDS(mech, MechSeemsFriend(player_mech, mech));
01025                         base[0] = id[0];
01026                         base[1] = id[1];
01027                 }
01028         }
01029 }
01030 
01031 static void sketch_tac_cliffs(char *buf, MAP * map, int sx, int sy, int wx,
01032                                                           int wy, int dispcols, int top_offset,
01033                                                           int left_offset, int cliff_size)
01034 {
01035         char *pos = buf + top_offset * dispcols + left_offset;
01036         int y, x;
01037         int oddcol1 = is_oddcol(sx);
01038 
01039         wx = MIN(wx, map->map_width - sx);
01040         wy = MIN(wy, map->map_height - sy);
01041         for(y = MAX(0, -sy); y < wy; y++) {
01042                 int ty = sy + y;
01043 
01044                 for(x = MAX(0, -sx); x < wx; x++) {
01045                         int tx = sx + x;
01046                         int oddcolx = is_oddcol(tx);
01047                         int elev = Elevation(map, tx, ty);
01048                         char *base = pos + tac_hex_offset(x, y, dispcols,
01049                                                                                           oddcol1);
01050                         char c;
01051 
01052                         /*
01053                          * Copy the elevation up to the top of the hex 
01054                          * so we can draw a bottom hex edge on every hex.
01055                          */
01056                         c = base[dispcols + 1];
01057                         if(base[0] == '*') {
01058                                 base[0] = '*';
01059                                 base[1] = '*';
01060                         } else if(isdigit((unsigned char) c)) {
01061                                 base[1] = c;
01062                         }
01063 
01064                         /*
01065                          * For each hex on the map check to see if each
01066                          * of it's 240, 180, and 120 hex sides is a cliff. 
01067                          * Don't check for cliffs between hexes that are on
01068                          * the tac map and those that are off of it.
01069                          */
01070 
01071                         if(x != 0 && (y < wy - 1 || oddcolx)
01072                            && abs(Elevation(map, tx - 1, ty + 1 - oddcolx)
01073                                           - elev) >= cliff_size) {
01074 
01075                                 base[dispcols - 1] = '|';
01076                         }
01077                         if(y < wy - 1 && abs(Elevation(map, tx, ty + 1) - elev)
01078                            >= cliff_size) {
01079                                 base[dispcols] = ',';
01080                                 base[dispcols + 1] = ',';
01081                         } else {
01082                                 base[dispcols] = '_';
01083                                 base[dispcols + 1] = '_';
01084                         }
01085                         if(x < wx - 1 && (y < wy - 1 || oddcolx)
01086                            && abs(Elevation(map, tx + 1, ty + 1 - oddcolx)
01087                                           - elev) >= cliff_size) {
01088                                 base[dispcols + 2] = '!';
01089                         }
01090                 }
01091         }
01092 }
01093 static void sketch_tac_dslz(char *buf, MAP * map, MECH * mech, int sx,
01094                                                         int sy, int wx, int wy, int dispcols,
01095                                                         int top_offset, int left_offset, int cliff_size,
01096                                                         int docolour)
01097 {
01098         char *pos = buf + top_offset * dispcols + left_offset;
01099         int y, x;
01100         int oddcol1 = is_oddcol(sx);
01101 
01102         wx = MIN(wx, map->map_width - sx);
01103         wy = MIN(wy, map->map_height - sy);
01104         for(y = MAX(0, -sy); y < wy; y++) {
01105                 int ty = sy + y;
01106 
01107                 for(x = MAX(0, -sx); x < wx; x++) {
01108                         int tx = sx + x;
01109                         char *base = pos + tac_hex_offset(x, y, dispcols, oddcol1);
01110 
01111                         if(ImproperLZ(mech, tx, ty))
01112                                 base[dispcols] = docolour ? '\241' : 'X';
01113                         else
01114                                 base[dispcols] = docolour ? '\240' : 'O';
01115                 }
01116         }
01117 }
01118 
01119 /*
01120  * Colourize a sketch tac map.  Uses dynmaically allocated buffers
01121  * which are overwritten on each call.
01122  */
01123 static char **colourize_tac_map(char const *sketch, int dispcols,
01124                                                                 int disprows)
01125 {
01126         static char *buf = NULL;
01127         static int buf_len = 5000;
01128         static char **lines = NULL;
01129         static int lines_len = 100;
01130         int pos = 0;
01131         int line = 0;
01132         unsigned char cur_colour = '\0';
01133         const char *line_start;
01134         char const *src = sketch;
01135 
01136         if(buf == NULL) {
01137                 Create(buf, char, buf_len);
01138         }
01139         if(lines == NULL) {
01140                 Create(lines, char *, lines_len);
01141         }
01142 
01143         line_start = (char *) src;
01144         lines[0] = buf;
01145         while (lines > 0) {
01146                 unsigned char new_colour;
01147                 unsigned char c = *src++;
01148 
01149                 if(c == '\0') {
01150                         /*
01151                          * End of line.
01152                          */
01153                         if(cur_colour != '\0') {
01154                                 buf[pos++] = '%';
01155                                 buf[pos++] = 'c';
01156                                 buf[pos++] = 'n';
01157                         }
01158                         buf[pos++] = '\0';
01159                         line++;
01160                         if(line >= disprows) {
01161                                 break;                  /* Done */
01162                         }
01163                         if(line + 1 >= lines_len) {
01164                                 lines_len *= 2;
01165                                 ReCreate(lines, char *, lines_len);
01166                         }
01167                         line_start += dispcols;
01168                         src = line_start;
01169                         lines[line] = buf + pos;
01170                         continue;
01171                 }
01172 
01173                 switch (c) {
01174                 case (unsigned char) '\242':    /* Colour Hack: Deep Water */
01175                         c = '~';
01176                         new_colour = custom_color_str[DWATER_IDX];
01177                         break;
01178 
01179                 case (unsigned char) '\241':    /* Colour Hack: improper LZ */
01180                         c = 'X';
01181                         new_colour = custom_color_str[BADLZ_IDX];
01182                         break;
01183                 case (unsigned char) '\240':    /* Colour Hack: proper LZ */
01184                         c = 'O';
01185                         new_colour = custom_color_str[GOODLZ_IDX];
01186                         break;
01187                 case '?':
01188                         c = '?';
01189                         new_colour = custom_color_str[UNKNOWN_IDX];
01190                         break;
01191 
01192                 case '$':                               /* Colour Hack: Drop Ship */
01193                         c = 'X';
01194                         new_colour = custom_color_str[DS_IDX];
01195                         break;
01196 
01197                 case '!':                               /* Cliff hex edge */
01198                         c = '/';
01199                         new_colour = custom_color_str[CLIFF_IDX];
01200                         break;
01201 
01202                 case '|':                               /* Cliff hex edge */
01203                         c = '\\';
01204                         new_colour = custom_color_str[CLIFF_IDX];
01205                         break;
01206 
01207                 case ',':                               /* Cliff hex edge */
01208                         c = '_';
01209                         new_colour = custom_color_str[CLIFF_IDX];
01210                         break;
01211                 case '*':                               /* mech itself. */
01212                         new_colour = custom_color_str[SELF_IDX];
01213                         break;
01214 
01215                 default:
01216                         if(islower(c)) {        /* Friendly con */
01217                                 new_colour = custom_color_str[FRIEND_IDX];
01218                         } else if(isupper(c)) { /* Enemy con */
01219                                 new_colour = custom_color_str[ENEMY_IDX];
01220                         } else if(isdigit(c)) { /* Elevation */
01221                                 new_colour = cur_colour;
01222                         } else {
01223                                 new_colour = TerrainColorChar(c, 0);
01224                         }
01225                         break;
01226                 }
01227 
01228                 if(isupper(new_colour) != isupper(cur_colour)) {
01229                         if(isupper(new_colour)) {
01230                                 buf[pos++] = '%';
01231                                 buf[pos++] = 'c';
01232                                 buf[pos++] = 'h';
01233                         } else {
01234                                 buf[pos++] = '%';
01235                                 buf[pos++] = 'c';
01236                                 buf[pos++] = 'n';
01237                                 cur_colour = '\0';
01238                         }
01239                 }
01240                 if(tolower(new_colour) != tolower(cur_colour)) {
01241                         buf[pos++] = '%';
01242                         buf[pos++] = 'c';
01243                         if(new_colour == '\0') {
01244                                 buf[pos++] = 'n';
01245                         } else if(new_colour == 'H') {
01246                                 buf[pos++] = 'n';
01247                                 buf[pos++] = '%';
01248                                 buf[pos++] = 'c';
01249                                 buf[pos++] = tolower(new_colour);
01250                         } else {
01251                                 buf[pos++] = tolower(new_colour);
01252                         }
01253                         cur_colour = new_colour;
01254                 }
01255                 buf[pos++] = c;
01256                 if(pos + 11 > buf_len) {
01257                         /*
01258                          * If we somehow run out of room then we don't
01259                          * bother to reallocate 'buf' and potentially have
01260                          * a bunch of invalid pointers in 'lines' to fix up.
01261                          * We just restart from scratch with a bigger 'buf'.
01262                          */
01263                         buf_len *= 2;
01264                         free(buf);
01265                         buf = NULL;
01266                         return colourize_tac_map(sketch, dispcols, disprows);
01267                 }
01268         }
01269         lines[line] = NULL;
01270         return lines;
01271 }
01272 
01273 /*
01274  * Draw a tac map for the TACTICAL and NAVIGATE commands.
01275  *
01276  * This used to be "one MOFO of a function" but has been simplified
01277  * in a number of ways.  One is that it used to statically allocated
01278  * buffers which limit the map drawn to MAP_DISPLAY_WIDTH hexes across
01279  * and 24 hexes down in size.  The return value should no longer be
01280  * freed with KillText().
01281  *
01282  * player   = dbref of player wanting map (mostly irrelevant)
01283  * mech     = mech player's in (or NULL, if on map) 
01284  * map      = map obj itself
01285  * cx       = middle of the map (x)
01286  * cy       = middle of the map (y)
01287  * wx       = width in x
01288  * wy       = width in y
01289  * labels   = bit array
01290  *    1 = the 'top numbers'
01291  *    2 = the 'side numbers'
01292  *    4 = navigate mode
01293  *    8 = show mech cliffs
01294  *   16 = show tank cliffs
01295  *   32 = show DS LZ's
01296  *
01297  * If navigate mode, wx and wy should be equal and odd.  Navigate maps
01298  * cannot have top or side labels.
01299  *
01300  */
01301 
01302 char **MakeMapText(dbref player, MECH * mech, MAP * map, int cx, int cy,
01303                                    int wx, int wy, int labels, int dohexlos)
01304 {
01305         int docolour = Ansimap(player);
01306         int dispcols;
01307         int disprows;
01308         int mapcols;
01309         int left_offset = 0;
01310         int top_offset = 0;
01311         int navigate = 0;
01312         int sx, sy;
01313         int i;
01314         char *base;
01315         int oddcol1;
01316         enum {
01317                 MAX_WIDTH = 40,
01318                 MAX_HEIGHT = 24,
01319                 TOP_LABEL = 3,
01320                 LEFT_LABEL = 4,
01321                 RIGHT_LABEL = 3
01322         };
01323         static char sketch_buf[((LEFT_LABEL + 1 + MAX_WIDTH * 3 + RIGHT_LABEL +
01324                                                          1) * (TOP_LABEL + 1 + MAX_HEIGHT * 2) + 2) * 5];
01325         static char *lines[(TOP_LABEL + 1 + MAX_HEIGHT * 2 + 1) * 5];
01326 
01327         if(labels & 4) {
01328                 navigate = 1;
01329                 labels = 0;
01330         }
01331 
01332         /*
01333          * Figure out the extent of the tac map to draw.  
01334          */
01335         wx = MIN(MAX_WIDTH, wx);
01336         wy = MIN(MAX_HEIGHT, wy);
01337 
01338         sx = cx - wx / 2;
01339         sy = cy - wy / 2;
01340         if(!navigate) {
01341                 /*
01342                  * Only allow navigate maps to include off map hexes.
01343                  */
01344                 sx = MAX(0, MIN(sx, map->map_width - wx));
01345                 sy = MAX(0, MIN(sy, map->map_height - wy));
01346                 wx = MIN(wx, map->map_width);
01347                 wy = MIN(wy, map->map_height);
01348         }
01349 
01350         mapcols = tac_dispcols(wx);
01351         dispcols = mapcols + 1;
01352         disprows = wy * 2 + 1;
01353         oddcol1 = is_oddcol(sx);
01354 
01355         if(navigate) {
01356                 if(oddcol1) {
01357                         /*
01358                          * Insert blank line at the top where we can put
01359                          * a "__" to make the navigate map look pretty.
01360                          */
01361                         top_offset = 1;
01362                         disprows++;
01363                 }
01364         } else {
01365                 /*
01366                  * Allow room for the labels.
01367                  */
01368                 if(labels & 1) {
01369                         left_offset = LEFT_LABEL;
01370                         dispcols += LEFT_LABEL + RIGHT_LABEL;
01371                 }
01372                 if(labels & 2) {
01373                         top_offset = TOP_LABEL;
01374                         disprows += TOP_LABEL;
01375                 }
01376         }
01377 
01378         /*
01379          * Create a sketch tac map including terrain and elevation.
01380          */
01381         sketch_tac_map(sketch_buf, map, mech, sx, sy, wx, wy, dispcols,
01382                                    top_offset, left_offset, docolour, dohexlos);
01383 
01384         /*
01385          * Draw the top and side labels.
01386          */
01387         if(labels & 1) {
01388                 int x;
01389 
01390                 for(x = 0; x < wx; x++) {
01391                         char scratch[4];
01392                         int label = sx + x;
01393 
01394                         if(label < 0 || label > 999) {
01395                                 continue;
01396                         }
01397                         sprintf(scratch, "%3d", label);
01398                         base = sketch_buf + left_offset + 1 + x * 3;
01399                         base[0] = scratch[0];
01400                         base[1 * dispcols] = scratch[1];
01401                         base[2 * dispcols] = scratch[2];
01402                 }
01403         }
01404 
01405         if(labels & 2) {
01406                 int y;
01407 
01408                 for(y = 0; y < wy; y++) {
01409                         int label = sy + y;
01410 
01411                         base = sketch_buf + (top_offset + 1 + y * 2)
01412                                 * dispcols;
01413                         if(label < 0 || label > 999) {
01414                                 continue;
01415                         }
01416 
01417                         sprintf(base, "%3d", label);
01418                         base[3] = ' ';
01419                         sprintf(base + (dispcols - RIGHT_LABEL - 1), "%3d", label);
01420                 }
01421         }
01422 
01423         if(labels & 8) {
01424                 if(mech != NULL) {
01425                         sketch_tac_ownmech(sketch_buf, map, mech, sx, sy, wx, wy,
01426                                                            dispcols, top_offset, left_offset);
01427                 }
01428                 sketch_tac_cliffs(sketch_buf, map, sx, sy, wx, wy, dispcols,
01429                                                   top_offset, left_offset, 3);
01430         } else if(labels & 16) {
01431                 if(mech != NULL) {
01432                         sketch_tac_ownmech(sketch_buf, map, mech, sx, sy, wx, wy,
01433                                                            dispcols, top_offset, left_offset);
01434                 }
01435                 sketch_tac_cliffs(sketch_buf, map, sx, sy, wx, wy, dispcols,
01436                                                   top_offset, left_offset, 2);
01437         } else if(labels & 32) {
01438                 if(mech != NULL) {
01439                         sketch_tac_ownmech(sketch_buf, map, mech, sx, sy, wx, wy,
01440                                                            dispcols, top_offset, left_offset);
01441                 }
01442                 sketch_tac_dslz(sketch_buf, map, mech, sx, sy, wx, wy, dispcols,
01443                                                 top_offset, left_offset, 2, docolour);
01444         } else if(mech != NULL) {
01445                 sketch_tac_mechs(sketch_buf, map, mech, sx, sy, wx, wy, dispcols,
01446                                                  top_offset, left_offset, docolour, labels);
01447         }
01448 
01449         if(navigate) {
01450                 int n = wx / 2;                 /* Hexagon radius */
01451 
01452                 /*
01453                  * Navigate hack: erase characters from the sketch map
01454                  * to turn it into a pretty hexagonal shaped map.
01455                  */
01456                 if(oddcol1) {
01457                         /*
01458                          * Don't need the last line in this case. 
01459                          */
01460                         disprows--;
01461                 }
01462 
01463                 for(i = 0; i < n; i++) {
01464                         int len;
01465 
01466                         base = sketch_buf + (i + 1) * dispcols + left_offset;
01467                         len = (n - i - 1) * 3 + 1;
01468                         memset(base, ' ', len);
01469                         base[len] = '_';
01470                         base[len + 1] = '_';
01471                         base[mapcols - len - 2] = '_';
01472                         base[mapcols - len - 1] = '_';
01473                         base[mapcols - len] = '\0';
01474 
01475                         base = sketch_buf + (disprows - i - 1) * dispcols + left_offset;
01476                         len = (n - i) * 3;
01477                         memset(base, ' ', len);
01478                         base[mapcols - len] = '\0';
01479                 }
01480 
01481                 memset(sketch_buf + left_offset, ' ', n * 3 + 1);
01482                 sketch_buf[left_offset + n * 3 + 1] = '_';
01483                 sketch_buf[left_offset + n * 3 + 2] = '_';
01484                 sketch_buf[left_offset + n * 3 + 3] = '\0';
01485         }
01486 
01487         if(docolour) {
01488                 /*
01489                  * If using colour then colourize the sketch map and
01490                  * return the result.
01491                  */
01492                 return colourize_tac_map(sketch_buf, dispcols, disprows);
01493         }
01494 
01495         /*
01496          * If not using colour, the sketch map can be used as is.
01497          */
01498         for(i = 0; i < disprows; i++) {
01499                 lines[i] = sketch_buf + dispcols * i;
01500         }
01501         lines[i] = NULL;
01502         return lines;
01503 }
01504 
01505 /* Draws the map for the player when they use the 
01506  * TACTICAL [C | T | L] [<BEARING> <RANGE> | <TARGET-ID>]
01507  * command inside a unit */
01508 void mech_tacmap(dbref player, void *data, char *buffer)
01509 {
01510         MECH *mech = (MECH *) data;
01511         int argc, i;
01512         short x, y;
01513         int mapx, mapy;
01514         char *args_vec[4];
01515         char **args = args_vec;
01516         MAP *mech_map;
01517         int displayHeight = MAP_DISPLAY_HEIGHT, displayWidth = MAP_DISPLAY_WIDTH;
01518         char *str;
01519         char **maptext;
01520         int flags = 3, dohexlos = 0;
01521 
01522         /* Basic checks for pilot and mech */
01523         cch(MECH_USUAL);
01524 
01525         /* Get the map info */
01526         mech_map = getMap(mech->mapindex);
01527         mapx = MechX(mech);
01528         mapy = MechY(mech);
01529 
01530         /* Various checks for conditions and system of mech */
01531         argc = mech_parseattributes(buffer, args, 4);
01532         DOCHECK(!MechTacRange(mech), "Your system seems to be inoperational.");
01533 
01534         if(MapIsDark(mech_map) || (MechType(mech) == CLASS_MW &&
01535                                                            mudconf.btech_mw_losmap))
01536                 dohexlos = 1;
01537 
01538         /* Check to see which type of tactical to display 
01539          * if they specified a particular one */
01540         if(argc > 0 && isalpha((unsigned char) args[0][0])
01541            && args[0][1] == '\0') {
01542 
01543                 switch (tolower((unsigned char) args[0][0])) {
01544                 case 'c':
01545                         flags |= 8;                     /* Show cliffs */
01546                         break;
01547 
01548                 case 't':
01549                         flags |= 16;            /* Show tank cliffs */
01550                         break;
01551 
01552                 case 'l':
01553                         dohexlos = 1;
01554                         break;
01555 
01556                 case 'b':
01557                         flags |= 32;
01558                         break;
01559 
01560                 default:
01561                         notify(player, "Invalid tactical map flag.");
01562                         return;
01563                 }
01564 
01565                 args++;
01566                 argc--;
01567         }
01568 
01569         DOCHECK(dohexlos
01570                         && (flags & (8 | 16 | 32)), "You can't see that much here!");
01571 
01572         if(!parse_tacargs(player, mech, args, argc, MechTacRange(mech), &x, &y))
01573                 return;
01574 
01575         /* Get the Tacsize attribute from
01576          * the player, if doesn't exist set the height and width to
01577          * default params. If it does exist, check the values and
01578          * make sure they are legit. */
01579         str = silly_atr_get(player, A_TACSIZE);
01580         if(!*str) {
01581                 displayHeight = MAP_DISPLAY_HEIGHT;
01582                 displayWidth = MAP_DISPLAY_WIDTH;
01583         } else if(sscanf(str, "%d %d", &displayHeight, &displayWidth) != 2 ||
01584                           displayHeight > 24 || displayHeight < 5 || displayWidth > 40 ||
01585                           displayWidth < 5) {
01586 
01587                 notify(player,
01588                            "Illegal Tacsize attribute. Must be in format "
01589                            "'Height Width' . Height : 5-24 Width : 5-40");
01590                 displayHeight = MAP_DISPLAY_HEIGHT;
01591                 displayWidth = MAP_DISPLAY_WIDTH;
01592         }
01593 
01594         /* Everything worked but lets check the mech's tac range
01595          * and the map size */
01596         displayHeight = (displayHeight <= 2 * MechTacRange(mech)
01597                                          ? displayHeight : 2 * MechTacRange(mech));
01598         displayWidth = (displayWidth <= 2 * MechTacRange(mech)
01599                                         ? displayWidth : 2 * MechTacRange(mech));
01600 
01601         displayHeight = (displayHeight <= mech_map->map_height)
01602                 ? displayHeight : mech_map->map_height;
01603         displayWidth = (displayWidth <= mech_map->map_width)
01604                 ? displayWidth : mech_map->map_width;
01605 
01606         set_colorscheme(player);
01607 
01608         /* Get the data to draw the map */
01609         maptext =
01610                 MakeMapText(player, mech, mech_map, x, y, displayWidth,
01611                                         displayHeight, flags, dohexlos);
01612 
01613         /* Draw the map for the player */
01614         for(i = 0; maptext[i]; i++)
01615                 notify(player, maptext[i]);
01616 }
01617 
01618 /* XXX Fix 'enterbase <dir>' */
01619 static void mech_enter_event(MUXEVENT * e)
01620 {
01621         MECH *mech = (MECH *) e->data, *tmpm = NULL;
01622         mapobj *mapo;
01623         MAP *map = getMap(mech->mapindex), *newmap;
01624         int target = (int) e->data2;
01625         int x, y;
01626 
01627         if(!(mapo = find_entrance_by_xy(map, MechX(mech), MechY(mech))))
01628                 return;
01629         if(!Started(mech) || Uncon(mech) || Jumping(mech) ||
01630            (MechType(mech) == CLASS_MECH && (Fallen(mech) || Standing(mech)))
01631            || OODing(mech) || (fabs(MechSpeed(mech)) * 5 >= MMaxSpeed(mech) &&
01632                                                    fabs(MMaxSpeed(mech)) >= MP1)
01633            || (MechType(mech) == CLASS_VTOL && AeroFuel(mech) <= 0))
01634                 return;
01635         if(!(newmap = getMap(mapo->obj)))
01636                 return;
01637         if(!find_entrance(newmap, target, &x, &y))
01638                 return;
01639 
01640         if(!can_pass_lock(mech->mynum, newmap->mynum, A_LENTER) &&
01641            (BuildIsSafe(newmap) || newmap->cf >= (newmap->cfmax / 2))) {
01642                 char *msg = silly_atr_get(newmap->mynum, A_FAIL);
01643                 if(!msg || !*msg)
01644                         msg = "The hangar is locked.";
01645                 mech_notify(mech, MECHALL, msg);
01646                 return;
01647         }
01648 
01649         StopBSuitSwarmers(FindObjectsData(mech->mapindex), mech, 1);
01650         mech_printf(mech, MECHALL, "You enter %s.", structure_name(mapo));
01651         MechLOSBroadcast(mech, tprintf("has entered %s at %d,%d.",
01652                                                                    structure_name(mapo), MechX(mech),
01653                                                                    MechY(mech)));
01654         MarkForLOSUpdate(mech);
01655         if(MechType(mech) == CLASS_MW && !In_Character(mapo->obj)) {
01656                 enter_mw_bay(mech, mapo->obj);
01657                 return;
01658         }
01659         if(MechCarrying(mech) > 0)
01660                 tmpm = getMech(MechCarrying(mech));
01661         mech_Rsetmapindex(GOD, (void *) mech, tprintf("%d", (int) mapo->obj));
01662         mech_Rsetxy(GOD, (void *) mech, tprintf("%d %d", x, y));
01663         MechLOSBroadcast(mech, tprintf("has entered %s at %d,%d.",
01664                                                                    structure_name(mapo), MechX(mech),
01665                                                                    MechY(mech)));
01666         loud_teleport(mech->mynum, mapo->obj);
01667         if(tmpm) {
01668                 mech_Rsetmapindex(GOD, (void *) tmpm, tprintf("%d", (int) mapo->obj));
01669                 mech_Rsetxy(GOD, (void *) tmpm, tprintf("%d %d", x, y));
01670                 loud_teleport(tmpm->mynum, mapo->obj);
01671         }
01672         auto_cal_mapindex(mech);
01673 }
01674 
01675 void mech_enterbase(dbref player, void *data, char *buffer)
01676 {
01677         MECH *mech = (MECH *) data;
01678         MAP *map, *newmap;
01679         int x, y;
01680         mapobj *mapo;
01681         char target, *tmpc;
01682         char *args[2];
01683         int argc;
01684 
01685         char fail_mesg[SBUF_SIZE];
01686 
01687         argc = mech_parseattributes(buffer, args, 2);
01688         DOCHECK(argc > 1, "Invalid arguments to command!");
01689         tmpc = args[0];
01690         if(argc > 0 && *tmpc && !(*(tmpc + 1)))
01691                 target = tolower(*tmpc);
01692         else
01693                 target = 0;
01694         cch(MECH_USUAL);
01695         map = getMap(mech->mapindex);
01696         /* For now, no dir checks */
01697         DOCHECK(Jumping(mech), "While in mid-jump? No way.");
01698         DOCHECK(MechType(mech) == CLASS_MECH && (Fallen(mech) ||
01699                                                                                          Standing(mech)),
01700                         "Crawl inside? I think not. Stand first.");
01701         DOCHECK(OODing(mech), "While in mid-flight? No way.");
01702         DOCHECK(MechType(mech) == CLASS_VTOL &&
01703                         AeroFuel(mech) <= 0, "You lack fuel to maneuver in!");
01704         DOCHECK(FlyingT(mech) &&
01705                         !Landed(mech),
01706                         "You need to land before you can enter the hangar.");
01707         DOCHECK(IsDS(mech),
01708                         "Heh, you're trying to be funny, right, a DropShip entering hangar?");
01709         DOCHECK(fabs(MechSpeed(mech)) * 5 >= MMaxSpeed(mech) &&
01710                         fabs(MMaxSpeed(mech)) >= MP1,
01711                         "You are moving too fast to enter the hangar!");
01712         DOCHECK(!(mapo =
01713                           find_entrance_by_xy(map, MechX(mech), MechY(mech))),
01714                         "You see nothing to enter here!");
01715         /* Wow, *gasp*, we got something to enter */
01716         if(!(newmap = FindObjectsData(mapo->obj))) {
01717                 mech_notify(mech, MECHALL,
01718                                         "You sense wrongness in fabric of space..");
01719                 SendError(tprintf
01720                                   ("Error: No map existing for mapindex #%d (@ %d,%d of #%d)",
01721                                    (int) mapo->obj, mapo->x, mapo->y, mech->mapindex));
01722                 return;
01723         }
01724         if(!find_entrance(newmap, target, &x, &y)) {
01725                 mech_notify(mech, MECHALL,
01726                                         "You sense wrongness in fabric of space..");
01727                 SendError(tprintf
01728                                   ("Error: No entrance existing for mapindex #%d (@ %d,%d of #%d)",
01729                                    (int) mapo->obj, mapo->x, mapo->y, mech->mapindex));
01730                 return;
01731         }
01732 
01733         if(!can_pass_lock(mech->mynum, newmap->mynum, A_LENTER) &&
01734            (BuildIsSafe(newmap) || newmap->cf >= (newmap->cfmax / 2))) {
01735 
01736                 /* Trigger FAIL & AFAIL */
01737                 memset(fail_mesg, 0, sizeof(fail_mesg));
01738                 snprintf(fail_mesg, LBUF_SIZE, "The hangar is locked.");
01739 
01740                 did_it(player, newmap->mynum, A_FAIL, fail_mesg, 0, NULL, A_AFAIL,
01741                            (char **) NULL, 0);
01742 
01743                 return;
01744         }
01745 
01746         DOCHECK(EnteringHangar(mech), "You are already entering the hangar!");
01747         /* XXX Check for other mechs in the hex possibly doing this as well (ick) */
01748         HexLOSBroadcast(map, MechX(mech), MechY(mech),
01749                                         "The doors at $h start to open..");
01750         MECHEVENT(mech, EVENT_ENTER_HANGAR, mech_enter_event, 18, (int) target);
01751 }

Generated on Mon May 28 04:25:22 2007 for BattletechMUX by  doxygen 1.4.7