src/hcode/btech/hudinfo.c

Go to the documentation of this file.
00001 /*
00002  * Copyright (c) 2002 Thomas Wouters <thomas@xs4all.net>
00003  *
00004  * HUDINFO support.
00005  */
00006 
00007 #include <string.h>
00008 #include <math.h>
00009 
00010 #include "config.h"
00011 #include "externs.h"
00012 #include "interface.h"
00013 
00014 #include "muxevent.h"
00015 #include "mech.h"
00016 #include "map.h"
00017 #include "map.los.h"
00018 #include "p.mech.utils.h"
00019 #include "p.mech.contacts.h"
00020 #include "failures.h"
00021 #include "p.mech.build.h"
00022 #include "p.mech.notify.h"
00023 #include "p.mech.update.h"
00024 #include "p.mech.move.h"
00025 #include "p.mech.los.h"
00026 #include "p.mech.status.h"
00027 
00028 extern void auto_reply(MECH * mech, char *buf);
00029 
00030 #ifdef HUDINFO_SUPPORT
00031 
00032 #include "hudinfo.h"
00033 
00034 void fake_hudinfo(dbref player, dbref cause, int key, char *arg)
00035 {
00036         notify(player, "HUDINFO does not work from scode or macros.");
00037 }
00038 
00039 HASHTAB hudinfo_cmdtab;
00040 
00041 void init_hudinfo(void)
00042 {
00043         HUDCMD *cmd;
00044 
00045         hashinit(&hudinfo_cmdtab, 20 * HASH_FACTOR);
00046 
00047         for(cmd = hudinfo_cmds; cmd->cmd; cmd++)
00048                 hashadd(cmd->cmd, (int *) cmd, &hudinfo_cmdtab);
00049 }
00050 
00051 static MECH *getMech_forPlayer(dbref player)
00052 {
00053         dbref inv, tmp;
00054         MECH *mech = NULL;
00055 
00056         if(Hardcode(player) && !Zombie(player))
00057                 mech = getMech(player);
00058 
00059         if(!mech) {
00060                 tmp = Location(player);
00061                 if(Hardcode(tmp) && !Zombie(tmp))
00062                         mech = getMech(tmp);
00063         }
00064 
00065         if(!mech) {
00066                 SAFE_DOLIST(inv, tmp, Contents(player)) {
00067                         if(Hardcode(inv) && !Zombie(inv))
00068                                 mech = getMech(inv);
00069                         if(mech)
00070                                 break;
00071                 }
00072         }
00073         return mech;
00074 }
00075 
00076 void do_hudinfo(DESC * d, char *arg)
00077 {
00078         char *subcmd;
00079         HUDCMD *cmd;
00080         MECH *mech = NULL;
00081 
00082         while (*arg && isspace(*arg))
00083                 arg++;
00084 
00085         if(!*arg) {
00086                 hudinfo_notify(d, NULL, NULL, "#HUD hudinfo version "
00087                                            HUD_PROTO_VERSION);
00088                 return;
00089         }
00090 
00091         if(strncmp(arg, "key=", 4) == 0) {
00092                 arg += 4;
00093                 if(!arg || strlen(arg) > 20) {
00094                         hudinfo_notify(d, "KEY", "E", "Invalid key");
00095                         return;
00096                 }
00097                 for(subcmd = arg; *subcmd; subcmd++) {
00098                         if(!isalnum(*subcmd)) {
00099                                 hudinfo_notify(d, "KEY", "E", "Invalid key");
00100                                 return;
00101                         }
00102                 }
00103                 strcpy(d->hudkey, arg);
00104                 hudinfo_notify(d, "KEY", "R", "Key set");
00105                 return;
00106         }
00107 
00108         if(!d->hudkey[0]) {
00109                 hudinfo_notify(d, "???", "E", "No session key set");
00110                 return;
00111         }
00112 
00113         subcmd = arg;
00114 
00115         while (*arg && !isspace(*arg)) {
00116                 if(!isalnum(*arg)) {
00117                         hudinfo_notify(d, "???", "E", "Invalid subcommand");
00118                         return;
00119                 }
00120                 arg++;
00121         }
00122 
00123         if(*arg) {
00124                 *arg++ = '\0';
00125         }
00126 
00127         while (*arg && isspace(*arg))
00128                 arg++;
00129 
00130         cmd = (HUDCMD *) hashfind(subcmd, &hudinfo_cmdtab);
00131         if(!cmd) {
00132                 hudinfo_notify(d, "???", "E",
00133                                            tprintf("%s: subcommand not found", subcmd));
00134                 return;
00135         }
00136 
00137         if(cmd->flag & HUDCMD_HASARG) {
00138                 if(!*arg) {
00139                         hudinfo_notify(d, cmd->msgclass, "E", "Not enough arguments");
00140                         return;
00141                 }
00142         } else if(*arg) {
00143                 hudinfo_notify(d, cmd->msgclass, "E", "Command takes no arguments");
00144                 return;
00145         }
00146 
00147         if(cmd->flag & HUDCMD_NEEDMECH) {
00148                 mech = getMech_forPlayer(d->player);
00149                 if(!mech) {
00150                         hudinfo_notify(d, cmd->msgclass, "E", "Not in a BattleTech unit");
00151                         return;
00152                 }
00153                 if((cmd->flag & HUDCMD_NONDEST) && Destroyed(mech)) {
00154                         hudinfo_notify(d, cmd->msgclass, "E", "You are destroyed!");
00155                         return;
00156                 }
00157                 if((cmd->flag & HUDCMD_STARTED) && !Started(mech)) {
00158                         hudinfo_notify(d, cmd->msgclass, "E", "Reactor is not online");
00159                         return;
00160                 }
00161                 if((cmd->flag & HUDCMD_AWAKE) &&
00162                    (MechStatus(mech) & (BLINDED | UNCONSCIOUS))) {
00163                         hudinfo_notify(d, cmd->msgclass, "E",
00164                                                    "You are unconscious....zzzzzzz");
00165                         return;
00166                 }
00167         }
00168 
00169         cmd->handler(d, mech, cmd->msgclass, arg);
00170         return;
00171 }
00172 
00173 static void FindRangeAndBearingToCenter(MECH * mech, float *rtc, int *btc)
00174 {
00175         float fx, fy;
00176 
00177         MapCoordToRealCoord(MechX(mech), MechY(mech), &fx, &fy);
00178         *rtc = FindHexRange(fx, fy, MechFX(mech), MechFY(mech));
00179         *btc = FindBearing(MechFX(mech), MechFY(mech), fx, fy);
00180 }
00181 
00182 static void hud_generalstatus(DESC * d, MECH * mech, char *msgclass,
00183                                                           char *args)
00184 {
00185         static char response[LBUF_SIZE];
00186         char fuel[15];
00187         char tstat[5];
00188         char jumpx[8], jumpy[8];
00189         int btc;
00190         float rtc;
00191 
00192         if(FlyingT(mech) && !AeroFreeFuel(mech))
00193                 sprintf(fuel, "%d", AeroFuel(mech));
00194         else
00195                 strcpy(fuel, "-");
00196 
00197         if(MechHasTurret(mech))
00198                 sprintf(tstat, "%d", AcceptableDegree(MechTurretFacing(mech)) - 180);
00199         else if((MechType(mech) == CLASS_MECH && !MechIsQuad(mech)) ||
00200                         MechType(mech) == CLASS_MW)
00201                 sprintf(tstat, "%d",
00202                                 MechStatus(mech) & TORSO_LEFT ? -60 : MechStatus(mech) &
00203                                 TORSO_RIGHT ? 60 : 0);
00204         else
00205                 strcpy(tstat, "-");
00206 
00207         if(Jumping(mech)) {
00208                 snprintf(jumpx, 8, "%d", MechGoingX(mech));
00209                 snprintf(jumpy, 8, "%d", MechGoingY(mech));
00210         } else {
00211                 strcpy(jumpx, "-");
00212                 strcpy(jumpy, "-");
00213         };
00214 
00215         FindRangeAndBearingToCenter(mech, &rtc, &btc);
00216 
00217         sprintf(response,
00218                         "%s,%d,%d,%d,%d,%d,%.2f,%.2f,%d,%d,%s,%.2f,%.2f,%.3f,%d,%s,%s,%s,%s",
00219                         MechIDS(mech, 0), MechX(mech), MechY(mech), MechZ(mech),
00220                         MechFacing(mech), MechDesiredFacing(mech),
00221                         MechSpeed(mech), MechDesiredSpeed(mech),
00222                         (int) (10 * MechPlusHeat(mech)),
00223                         (int) (10 * MechMinusHeat(mech)),
00224                         fuel, MechVerticalSpeed(mech), MechVerticalSpeed(mech),
00225                         rtc, btc, tstat, getStatusString(mech, 2), jumpx, jumpy);
00226 
00227         hudinfo_notify(d, msgclass, "R", response);
00228 }
00229 
00230 static char *hud_getweaponstatus(MECH * mech, int sect, int crit, int data)
00231 {
00232         static char wstatus[12];
00233 
00234         if(PartIsBroken(mech, sect, crit))
00235                 return "*";
00236         if(PartIsDisabled(mech, sect, crit))
00237                 return "D";
00238         switch (PartTempNuke(mech, sect, crit)) {
00239         case FAIL_JAMMED:
00240                 return "J";
00241         case FAIL_SHORTED:
00242                 return "S";
00243         case FAIL_DUD:
00244                 return "d";
00245         case FAIL_EMPTY:
00246                 return "E";
00247         case FAIL_AMMOJAMMED:
00248                 return "A";
00249         case FAIL_DESTROYED:
00250                 return "*";
00251         }
00252         if(GetPartFireMode(mech, sect, crit) & IS_JETTISONED_MODE)
00253                 return "j";
00254         if(data) {
00255                 sprintf(wstatus, "%d", data / WEAPON_TICK);
00256                 return wstatus;
00257         }
00258         return "R";
00259 }
00260 
00261 static char *hud_getfiremode(MECH * mech, int sect, int crit, int type)
00262 {
00263         int mode = GetPartFireMode(mech, sect, crit);
00264         static char wmode[30];
00265         char *p = wmode;
00266 
00267         if(mode & RAC_TWOSHOT_MODE)
00268                 *p++ = '2';
00269         if(mode & RAC_FOURSHOT_MODE)
00270                 *p++ = '4';
00271         if(mode & RAC_SIXSHOT_MODE)
00272                 *p++ = '6';
00273         if(mode & WILL_JETTISON_MODE)
00274                 *p++ = 'B';
00275         if(mode & GATTLING_MODE)
00276                 *p++ = 'G';
00277         if(mode & HOTLOAD_MODE)
00278                 *p++ = 'H';
00279         if(mode & RFAC_MODE)
00280                 *p++ = 'R';
00281         if((mode & ON_TC) && !(MechCritStatus(mech) & TC_DESTROYED))
00282                 *p++ = 'T';
00283         if(mode & ULTRA_MODE)
00284                 *p++ = 'U';
00285         if(mode & HEAT_MODE)
00286                 *p++ = 'h';
00287 
00288         if(mode & (OS_USED | ROCKET_FIRED))
00289                 *p++ = 'o';
00290         else if((mode & OS_MODE) || (MechWeapons[type].special & ROCKET))
00291                 *p++ = 'O';
00292 
00293         if(MechWeapons[type].special & INARC)
00294                 *p++ = 'I';
00295         if(MechWeapons[type].special & NARC)
00296                 *p++ = 'N';
00297         if(MechWeapons[type].special & STREAK)
00298                 *p++ = 'S';
00299 
00300         if(MechWeapons[type].special & AMS) {
00301                 if(MechStatus(mech) & AMS_ENABLED)
00302                         *p++ = 'A';
00303                 else
00304                         *p++ = 'a';
00305         }
00306 
00307         /* XXX Do enhanced damage */
00308 
00309         if(p == wmode)
00310                 *p++ = '-';
00311 
00312         *p = '\0';
00313         return wmode;
00314 }
00315 
00316 static char *hud_getammomode(MECH * mech, int mode)
00317 {
00318         static char amode[20];
00319         char *p = amode;
00320 
00321         if(mode & SGUIDED_MODE)
00322                 *p++ = 'G';
00323         if(mode & SWARM1_MODE)
00324                 *p++ = '1';
00325         if(mode & ARTEMIS_MODE)
00326                 *p++ = 'A';
00327         if(mode & CLUSTER_MODE)
00328                 *p++ = 'C';
00329         if(mode & INARC_ECM_MODE)
00330                 *p++ = 'E';
00331         if(mode & AC_FLECHETTE_MODE)
00332                 *p++ = 'F';
00333         if(mode & INARC_HAYWIRE_MODE)
00334                 *p++ = 'H';
00335         if(mode & INFERNO_MODE)
00336                 *p++ = 'I';
00337         if(mode & LBX_MODE)
00338                 *p++ = 'L';
00339         if(mode & MINE_MODE)
00340                 *p++ = 'M';
00341         if(mode & NARC_MODE)
00342                 *p++ = 'N';
00343         if(mode & AC_PRECISION_MODE)
00344                 *p++ = 'P';
00345         if(mode & SWARM_MODE)
00346                 *p++ = 'S';
00347         if(mode & AC_AP_MODE)
00348                 *p++ = 'a';
00349         if(mode & INARC_EXPLO_MODE)
00350                 *p++ = 'X';
00351         if(mode & AC_INCENDIARY_MODE)
00352                 *p++ = 'e';
00353         if(mode & SMOKE_MODE)
00354                 *p++ = 's';
00355         if(mode & STINGER_MODE)
00356                 *p++ = 'T';
00357         if(mode & AC_CASELESS_MODE)
00358                 *p++ = 'U';
00359 
00360         if(p == amode)
00361                 *p++ = '-';
00362         *p = '\0';
00363         return amode;
00364 }
00365 
00366 static void hud_weapons(DESC * d, MECH * mech, char *msgclass, char *args)
00367 {
00368         int sect, weapcount, i, weapnum = -1;
00369         unsigned char weaparray[MAX_WEAPS_SECTION];
00370         unsigned char weapdata[MAX_WEAPS_SECTION];
00371         int critical[MAX_WEAPS_SECTION];
00372         char response[LBUF_SIZE];
00373 
00374         UpdateRecycling(mech);
00375 
00376         for(sect = 0; sect < NUM_SECTIONS; sect++) {
00377                 weapcount = FindWeapons(mech, sect, weaparray, weapdata, critical);
00378                 if(weapcount <= 0)
00379                         continue;
00380                 for(i = 0; i < weapcount; i++) {
00381                         weapnum++;
00382                         sprintf(response, "%d,%d,%d,%s%s,%s,%s,%s",
00383                                         weapnum,
00384                                         weaparray[i],
00385                                         GetPartBrand(mech, sect, critical[i]),
00386                                         ShortArmorSectionString(MechType(mech), MechMove(mech),
00387                                                                                         sect), GetPartFireMode(mech, sect,
00388                                                                                                                                    critical
00389                                                                                                                                    [i]) &
00390                                         REAR_MOUNT ? "r" : "", hud_getweaponstatus(mech, sect,
00391                                                                                                                            critical[i],
00392                                                                                                                            weapdata[i]),
00393                                         hud_getfiremode(mech, sect, critical[i], weaparray[i]),
00394                                         hud_getammomode(mech,
00395                                                                         GetPartAmmoMode(mech, sect,
00396                                                                                                         critical[i])));
00397                         hudinfo_notify(d, msgclass, "L", response);
00398                 }
00399         }
00400         hudinfo_notify(d, msgclass, "D", "Done");
00401 }
00402 
00403 static int get_weaponmodes(int weapindx, char *firemodes, char *ammomodes,
00404                                                    char *damagetype)
00405 {
00406         int spec = MechWeapons[weapindx].special;
00407 
00408         if(spec & PCOMBAT)
00409                 return 0;
00410 
00411         switch (MechWeapons[weapindx].type) {
00412         case TMISSILE:
00413                 strcat(damagetype, "M");
00414                 if(spec & AMS) {
00415                         strcat(damagetype, "d");
00416                         strcat(firemodes, "Aa");
00417                         break;
00418                 }
00419                 if(spec & INARC) {
00420                         strcat(firemodes, "I");
00421                         strcat(ammomodes, "EHe");
00422                         break;
00423                 }
00424                 if(spec & NARC) {
00425                         strcat(firemodes, "N");
00426                         break;
00427                 }
00428                 if(spec & IDF) {                /* LRM */
00429                         strcat(ammomodes, "1ACMNSs");
00430                         strcat(damagetype, "g");
00431                         strcat(firemodes, "Hi");
00432                 } else if(spec & MRM)   /* MRM */
00433                         strcat(damagetype, "g");
00434                 else                                    /* SRM/SR_DFM */
00435                         strcat(ammomodes, "AIN");
00436                 if(spec & DFM)
00437                         strcat(damagetype, "D");
00438                 if(spec & ELRM)
00439                         strcat(damagetype, "e");
00440                 if(spec & STREAK)
00441                         strcat(firemodes, "S");
00442                 break;
00443         case TAMMO:
00444                 if(spec & GAUSS) {
00445                         strcat(damagetype, "G");
00446                         if(spec & HVYGAUSS)
00447                                 strcat(damagetype, "H");
00448                         break;
00449                 }
00450                 strcat(damagetype, "B");
00451 
00452                 if(spec & CASELESS)
00453                         strcat(damagetype, "C");
00454                 if(spec & HYPER)
00455                         strcat(damagetype, "Y");
00456                 if(spec & RAC)
00457                         strcat(firemodes, "246");
00458                 if(spec & GMG)
00459                         strcat(firemodes, "G");
00460                 if(spec & RFAC) {
00461                         strcat(firemodes, "R");
00462                         strcat(ammomodes, "FPai");
00463                 }
00464                 if(spec & LBX)
00465                         strcat(ammomodes, "L");
00466                 if(spec & ULTRA)
00467                         strcat(firemodes, "U");
00468                 break;
00469         case TARTILLERY:
00470                 strcat(damagetype, "Ag");
00471                 strcat(firemodes, "Hi");
00472                 strcat(ammomodes, "CMs");
00473                 break;
00474         case TBEAM:
00475                 strcat(damagetype, "E");
00476                 if(spec & HVYW)
00477                         strcat(damagetype, "h");
00478                 if(spec & PULSE)
00479                         strcat(damagetype, "p");
00480                 if(spec & CHEAT)
00481                         strcat(firemodes, "h");
00482                 if(spec & A_POD)
00483                         strcat(damagetype, "a");
00484                 break;
00485         }
00486         if(spec & NOSPA)
00487                 ammomodes[0] = '\0';
00488         return 1;
00489 }
00490 
00491 static void hud_weaponlist(DESC * d, MECH * mech, char *msgclass, char *args)
00492 {
00493         int i;
00494         char firemodes[30] = "";
00495         char ammomodes[20] = "";
00496         char damagetype[10] = "";
00497         char response[LBUF_SIZE];
00498         struct weapon_struct *w;
00499 
00500         for(i = 0; i < num_def_weapons; i++) {
00501                 firemodes[0] = ammomodes[0] = damagetype[0] = '\0';
00502                 if(!get_weaponmodes(i, firemodes, ammomodes, damagetype))
00503                         continue;
00504 
00505                 if(strlen(firemodes) == 0)
00506                         strcat(firemodes, "-");
00507                 if(strlen(ammomodes) == 0)
00508                         strcat(ammomodes, "-");
00509 
00510                 w = &MechWeapons[i];
00511                 sprintf(response,
00512                                 "%d,%s,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%s,%s,%s,%d", i,
00513                                 w->name, w->min, w->shortrange, w->medrange, w->longrange,
00514                                 w->min_water, w->shortrange_water, w->medrange_water,
00515                                 w->longrange_water, w->criticals, w->weight, w->damage,
00516                                 w->vrt, firemodes, ammomodes, damagetype, w->heat * 10);
00517                 hudinfo_notify(d, msgclass, "L", response);
00518         }
00519 
00520         hudinfo_notify(d, msgclass, "D", "Done");
00521 }
00522 
00523 static void hud_limbstatus(DESC * d, MECH * mech, char *msgclass, char *args)
00524 {
00525 
00526         int locs[] = { RLEG, LLEG, RARM, LARM };
00527         int todo = 3;
00528 
00529         UpdateRecycling(mech);
00530 
00531         if(MechType(mech) == CLASS_MECH) {
00532                 for(; todo >= 0; todo--) {
00533                         char *sect = ShortArmorSectionString(MechType(mech),
00534                                                                                                  MechMove(mech), locs[todo]);
00535                         char status[10];
00536 
00537                         if(SectIsDestroyed(mech, locs[todo]))
00538                                 strcpy(status, "*");
00539                         else if(MechSections(mech)[locs[todo]].recycle > 0)
00540                                 sprintf(status, "%d",
00541                                                 MechSections(mech)[locs[todo]].recycle / WEAPON_TICK);
00542                         else
00543                                 strcpy(status, "R");
00544 
00545                         hudinfo_notify(d, msgclass, "L", tprintf("%s,%s", sect, status));
00546                 }
00547         }
00548         hudinfo_notify(d, msgclass, "D", "Done");
00549 }
00550 
00551 static void hud_ammostatus(DESC * d, MECH * mech, char *msgclass, char *args)
00552 {
00553         unsigned char weapnums[8 * MAX_WEAPS_SECTION];
00554         unsigned short curamm[8 * MAX_WEAPS_SECTION];
00555         unsigned short maxamm[8 * MAX_WEAPS_SECTION];
00556         unsigned int ammomode[8 * MAX_WEAPS_SECTION];
00557         int i, ammonum;
00558         char response[LBUF_SIZE];
00559 
00560         ammonum = FindAmmunition(mech, weapnums, curamm, maxamm, ammomode, 1);
00561 
00562         for(i = 0; i < ammonum; i++) {
00563                 sprintf(response, "%d,%d,%s,%d,%d", i, weapnums[i],
00564                                 hud_getammomode(mech, ammomode[i]), curamm[i], maxamm[i]);
00565                 hudinfo_notify(d, msgclass, "L", response);
00566         }
00567         hudinfo_notify(d, msgclass, "D", "Done");
00568 }
00569 
00570 static char hud_typechar(MECH * mech)
00571 {
00572 
00573         if(MechMove(mech) == MOVE_NONE)
00574                 return 'i';
00575 
00576         switch (MechType(mech)) {
00577         case CLASS_MECH:
00578                 if(MechMove(mech) == MOVE_QUAD)
00579                         return 'Q';
00580                 return 'B';
00581         case CLASS_VEH_GROUND:
00582         case CLASS_VEH_NAVAL:
00583                 switch (MechMove(mech)) {
00584                 case MOVE_TRACK:
00585                         return 'T';
00586                 case MOVE_WHEEL:
00587                         return 'W';
00588                 case MOVE_HOVER:
00589                         return 'H';
00590                 case MOVE_HULL:
00591                         return 'N';
00592                 case MOVE_FOIL:
00593                         return 'Y';
00594                 case MOVE_SUB:
00595                         return 'U';
00596                 default:
00597                         SendError(tprintf("Unknown movement type on vehicle #%d: %d",
00598                                                           mech->mynum, MechMove(mech)));
00599                         return '?';
00600                 }
00601         case CLASS_VTOL:
00602                 return 'V';
00603         case CLASS_AERO:
00604                 return 'F';
00605         case CLASS_DS:
00606                 return 'A';
00607         case CLASS_SPHEROID_DS:
00608                 return 'D';
00609         case CLASS_MW:
00610                 return 'I';
00611         case CLASS_BSUIT:
00612                 return 'S';
00613         }
00614         SendError(tprintf("Unknown unit type on unit #%d: %d (move %d)",
00615                                           mech->mynum, MechType(mech), MechMove(mech)));
00616         return '?';
00617 }
00618 
00619 static float MaxSettableSpeed(MECH * mech)
00620 {
00621         int maxspeed = MMaxSpeed(mech);
00622 
00623         if(MechMove(mech) == MOVE_VTOL)
00624                 maxspeed = sqrt((float) maxspeed * maxspeed -
00625                                                 MechVerticalSpeed(mech) * MechVerticalSpeed(mech));
00626 
00627         maxspeed = maxspeed > 0.0 ? maxspeed : 0.0;
00628 
00629         if((MechSpecials(mech) & TRIPLE_MYOMER_TECH) && MechHeat(mech) >= 9.)
00630                 maxspeed = ceil((rint((maxspeed / 1.5) / MP1) + 1) * 1.5) * MP1;
00631         return maxspeed;
00632 }
00633 
00634 static float MaxVerticalSpeed(MECH * mech)
00635 {
00636         int maxspeed = MMaxSpeed(mech);
00637 
00638         if(MechMove(mech) != MOVE_VTOL)
00639                 return 0.0;
00640 
00641         maxspeed = sqrt((float) maxspeed * maxspeed -
00642                                         MechDesiredSpeed(mech) * MechDesiredSpeed(mech));
00643         return maxspeed;
00644 }
00645 
00646 static char *hud_advtech(MECH * mech)
00647 {
00648         static char advtech[30];
00649         char *p = advtech;
00650         int spec = MechSpecials(mech);
00651 
00652         if(spec & ECM_TECH)
00653                 *p++ = 'E';
00654         if(spec & BEAGLE_PROBE_TECH)
00655                 *p++ = 'B';
00656         if(spec & MASC_TECH)
00657                 *p++ = 'M';
00658         if(spec & AA_TECH)
00659                 *p++ = 'R';
00660         if(spec & SLITE_TECH)
00661                 *p++ = 'S';
00662         if(spec & TRIPLE_MYOMER_TECH)
00663                 *p++ = 't';
00664 
00665         spec = MechSpecials2(mech);
00666         if(spec & ANGEL_ECM_TECH)
00667                 *p++ = 'A';
00668         if(spec & NULLSIGSYS_TECH)
00669                 *p++ = 'N';
00670         if(spec & BLOODHOUND_PROBE_TECH)
00671                 *p++ = 'b';
00672         if(spec & STEALTH_ARMOR_TECH)
00673                 *p++ = 's';
00674 
00675         spec = MechInfantrySpecials(mech);
00676         if(spec & FC_INFILTRATORII_STEALTH_TECH) {
00677                 *p++ = 'I';
00678                 *p++ = 'P';
00679         }
00680         if(spec & CAN_JETTISON_TECH)
00681                 *p++ = 'J';
00682         if(spec & DC_KAGE_STEALTH_TECH)
00683                 *p++ = 'K';
00684         if(spec & INF_ANTILEG_TECH)
00685                 *p++ = 'L';
00686         if(spec & INF_SWARM_TECH)
00687                 *p++ = 'W';
00688         if(spec & FWL_ACHILEUS_STEALTH_TECH)
00689                 *p++ = 'a';
00690         if(spec & INF_MOUNT_TECH)
00691                 *p++ = 'f';
00692         if(spec & FC_INFILTRATOR_STEALTH_TECH)
00693                 *p++ = 'i';
00694         if(spec & MUST_JETTISON_TECH)
00695                 *p++ = 'j';
00696         if(spec & CS_PURIFIER_STEALTH_TECH)
00697                 *p++ = 'p';
00698 
00699         if(HasC3i(mech))
00700                 *p++ = 'C';
00701         if(HasTAG(mech))
00702                 *p++ = 'T';
00703         if(HasC3s(mech))
00704                 *p++ = 'c';
00705         if(HasC3m(mech))
00706                 *p++ = 'm';
00707 
00708         if(p == advtech)
00709                 *p++ = '-';
00710 
00711         *p = '\0';
00712         return advtech;
00713 }
00714 
00715 static void hud_templateinfo(DESC * d, MECH * mech, char *msgclass,
00716                                                          char *args)
00717 {
00718         char response[LBUF_SIZE];
00719         char fuel[20];
00720 
00721         if(FlyingT(mech) && AeroFuelOrig(mech))
00722                 sprintf(fuel, "%d", AeroFuelOrig(mech));
00723         else
00724                 strcpy(fuel, "-");
00725 
00726         sprintf(response, "%c,%s,%s,%.3f,%.3f,%.3f,%.3f,%s,%d,%s",
00727                         hud_typechar(mech), MechType_Ref(mech), MechType_Name(mech),
00728                         WalkingSpeed(MaxSettableSpeed(mech)), MaxSettableSpeed(mech),
00729                         -WalkingSpeed(MaxSettableSpeed(mech)),
00730                         MaxVerticalSpeed(mech), fuel, MechRealNumsinks(mech),
00731                         hud_advtech(mech));
00732         hudinfo_notify(d, msgclass, "R", response);
00733 }
00734 
00735 static void hud_templatearmor(DESC * d, MECH * mech, char *msgclass,
00736                                                           char *args)
00737 {
00738         char response[LBUF_SIZE];
00739         int sect;
00740 
00741         for(sect = 0; sect < NUM_SECTIONS; sect++) {
00742                 if(GetSectOInt(mech, sect)) {
00743                         sprintf(response, "%s,%d,%d,%d",
00744                                         ShortArmorSectionString(MechType(mech), MechMove(mech),
00745                                                                                         sect), GetSectOArmor(mech, sect),
00746                                         GetSectORArmor(mech, sect), GetSectOInt(mech, sect));
00747                         hudinfo_notify(d, msgclass, "L", response);
00748                 }
00749         }
00750         hudinfo_notify(d, msgclass, "D", "Done");
00751 }
00752 
00753 static void hud_armorstatus(DESC * d, MECH * mech, char *msgclass, char *args)
00754 {
00755         char response[LBUF_SIZE];
00756         int sect;
00757 
00758         for(sect = 0; sect < NUM_SECTIONS; sect++) {
00759                 if(GetSectOInt(mech, sect)) {
00760                         sprintf(response, "%s,%d,%d,%d",
00761                                         ShortArmorSectionString(MechType(mech), MechMove(mech),
00762                                                                                         sect), GetSectArmor(mech, sect),
00763                                         GetSectRArmor(mech, sect), GetSectInt(mech, sect));
00764                         hudinfo_notify(d, msgclass, "L", response);
00765                 }
00766         }
00767         hudinfo_notify(d, msgclass, "D", "Done");
00768 }
00769 
00770 static char *hud_arcstring(int arc)
00771 {
00772         static char arcstr[5];
00773         char *p = arcstr;
00774 
00775         if(arc & FORWARDARC)
00776                 *p++ = '*';
00777         if(arc & LSIDEARC)
00778                 *p++ = 'l';
00779         if(arc & RSIDEARC)
00780                 *p++ = 'r';
00781         if(arc & REARARC)
00782                 *p++ = 'v';
00783         if(arc & TURRETARC)
00784                 *p++ = 't';
00785 
00786         if(p == arcstr)
00787                 *p++ = '-';
00788 
00789         *p = '\0';
00790         return arcstr;
00791 }
00792 
00793 static char *hud_sensorstring(MECH * mech, int losflag)
00794 {
00795         if((losflag & MECHLOSFLAG_SEESP) && (losflag & MECHLOSFLAG_SEESS))
00796                 return "PS";
00797         if(losflag & MECHLOSFLAG_SEESP)
00798                 return "P";
00799         if(losflag & MECHLOSFLAG_SEESS)
00800                 return "S";
00801         return "-";
00802 }
00803 
00804 static void hud_contacts(DESC * d, MECH * mech, char *msgclass, char *args)
00805 {
00806         char response[LBUF_SIZE];
00807         MECH *other;
00808         MAP *map = getMap(mech->mapindex);
00809         int i, losflag, bearing, btc, weaponarc, x, y;
00810         float range, rtc;
00811         char jumph[12];
00812         char *mechname, *constat;
00813 
00814         if(!map) {
00815                 hudinfo_notify(d, msgclass, "E", "You are on no map");
00816                 return;
00817         }
00818 
00819         for(i = 0; i < map->first_free; i++) {
00820                 if(map->mechsOnMap[i] == mech->mynum || map->mechsOnMap[i] == -1)
00821                         continue;
00822 
00823                 other = (MECH *) FindObjectsData(map->mechsOnMap[i]);
00824                 if(!other || !Good_obj(other->mynum))
00825                         continue;
00826 
00827                 range = FlMechRange(map, mech, other);
00828                 x = MechX(other);
00829                 y = MechY(other);
00830                 losflag = InLineOfSight(mech, other, x, y, range);
00831                 if(!losflag)
00832                         continue;
00833                 bearing = FindBearing(MechFX(mech), MechFY(mech), MechFX(other),
00834                                                           MechFY(other));
00835                 weaponarc = InWeaponArc(mech, MechFX(other), MechFY(other));
00836 
00837                 if(Jumping(other))
00838                         sprintf(jumph, "%d", MechJumpHeading(other));
00839                 else
00840                         strcpy(jumph, "-");
00841 
00842                 FindRangeAndBearingToCenter(other, &rtc, &btc);
00843 
00844                 if(!InLineOfSight_NB(mech, other, MechX(other), MechY(other), 0.0))
00845                         mechname = "something";
00846                 else
00847                         mechname = silly_atr_get(other->mynum, A_MECHNAME);
00848 
00849                 if(!mechname || !*mechname)
00850                         mechname = "-";
00851 
00852                 constat = getStatusString(other, !MechSeemsFriend(mech, other));
00853                 if(strlen(constat) == 0)
00854                         constat = "-";
00855 
00856                 sprintf(response,
00857                                 "%s,%s,%s,%c,%s,%d,%d,%d,%.3f,%d,%.3f,%.3f,%d,%s,%.3f,%d,%d,%.0f,%s",
00858                                 MechIDS(other, MechSeemsFriend(mech, other)),
00859                                 hud_arcstring(weaponarc), hud_sensorstring(mech, losflag),
00860                                 hud_typechar(other), mechname, MechX(other),
00861                                 MechY(other), MechZ(other), range, bearing, MechSpeed(other),
00862                                 MechVerticalSpeed(other), MechVFacing(other), jumph, rtc, btc,
00863                                 MechTons(other), MechHeat(other), constat);
00864                 hudinfo_notify(d, msgclass, "L", response);
00865         }
00866         hudinfo_notify(d, msgclass, "D", "Done");
00867 }
00868 
00869 static char *building_status(MAP * map, int locked)
00870 {
00871         static char buildingstatus[7];
00872         char *p = buildingstatus;
00873 
00874         if(BuildIsCS(map))
00875                 *p++ = 'C';
00876 
00877         if(locked)
00878                 *p++ = 'E';
00879         else
00880                 *p++ = 'F';
00881 
00882         if(BuildIsHidden(map))
00883                 *p++ = 'H';
00884 
00885         if(BuildIsSafe(map) || (locked && BuildIsCS(map)))
00886                 *p++ = 'X';
00887         else if(locked)
00888                 *p++ = 'x';
00889 
00890         if(p == buildingstatus)
00891                 *p++ = '-';
00892 
00893         *p = '\0';
00894 
00895         return buildingstatus;
00896 }
00897 
00898 static void hud_building_contacts(DESC * d, MECH * mech, char *msgclass,
00899                                                                   char *args)
00900 {
00901         char response[LBUF_SIZE];
00902         MAP *map = getMap(mech->mapindex);
00903         MAP *building_map;
00904         char *building_name;
00905         mapobj *building;
00906         float fx, fy, range;
00907         int z, losflag, locked, bearing, weaponarc;
00908         char new[LBUF_SIZE];
00909 
00910         if(!map) {
00911                 hudinfo_notify(d, msgclass, "E", "You are on no map");
00912                 return;
00913         }
00914 
00915         for(building = first_mapobj(map, TYPE_BUILD); building;
00916                 building = next_mapobj(building)) {
00917 
00918                 MapCoordToRealCoord(building->x, building->y, &fx, &fy);
00919                 z = Elevation(map, building->x, building->y) + 1;
00920                 range = FindRange(MechFX(mech), MechFY(mech), MechFZ(mech), fx, fy,
00921                                                   ZSCALE * z);
00922 
00923                 if(!building->obj)
00924                         continue;
00925 
00926                 building_map = getMap(building->obj);
00927                 if(!building_map)
00928                         continue;
00929 
00930                 losflag = InLineOfSight(mech, NULL, building->x, building->y, range);
00931                 if(!losflag || (losflag & MECHLOSFLAG_BLOCK))
00932                         continue;
00933 
00934                 if(BuildIsInvis(building_map))
00935                         continue;
00936 
00937                 locked = !can_pass_lock(mech->mynum, building->obj, A_LENTER);
00938                 if(locked && BuildIsHidden(building_map))
00939                         continue;
00940 
00941                 bearing = FindBearing(MechFX(mech), MechFY(mech), fx, fy);
00942                 weaponarc = InWeaponArc(mech, fx, fy);
00943                 building_name = silly_atr_get(building->obj, A_MECHNAME);
00944                 if(!building_name || !*building_name) {
00945                         strncpy(new, Name(building->obj), LBUF_SIZE-1);
00946                         building_name = strip_ansi_r(new,Name(building->obj),strlen(Name(building->obj)));
00947                 }
00948 
00949                 if(!building_name || !*building_name)
00950                         building_name = "-";
00951 
00952                 sprintf(response, "%s,%s,%d,%d,%d,%f,%d,%d,%d,%s",
00953                                 hud_arcstring(weaponarc), building_name, building->x,
00954                                 building->y, z, range, bearing, building_map->cf,
00955                                 building_map->cfmax, building_status(building_map, locked));
00956                 hudinfo_notify(d, msgclass, "L", response);
00957         }
00958         hudinfo_notify(d, msgclass, "D", "Done");
00959 
00960 };
00961 
00962 static char hud_damstr[] = "OoxX*?";
00963 static char hud_damagechar(MECH * mech, int sect, int type)
00964 {
00965         int dummy;
00966 
00967         switch (type) {
00968         case 1:
00969                 if(GetSectOArmor(mech, sect))
00970                         return hud_damstr[ArmorEvaluateSerious(mech, sect, 1, &dummy)];
00971                 return '-';
00972         case 2:
00973                 if(GetSectOInt(mech, sect))
00974                         return hud_damstr[ArmorEvaluateSerious(mech, sect, 2, &dummy)];
00975                 return '-';
00976         case 4:
00977                 if(GetSectORArmor(mech, sect))
00978                         return hud_damstr[ArmorEvaluateSerious(mech, sect, 4, &dummy)];
00979                 return '-';
00980         }
00981         return '?';
00982 }
00983 
00984 static MECH *hud_scantarget(DESC * d, MECH * mech, char *msgclass, char *args)
00985 {
00986         MECH *targ;
00987         float range;
00988 
00989         if(!MechScanRange(mech)) {
00990                 hudinfo_notify(d, msgclass, "E",
00991                                            "Your system seems to be inoperational");
00992                 return NULL;
00993         }
00994 
00995         if(strlen(args) != 2 ||
00996            !(targ = getMech(FindTargetDBREFFromMapNumber(mech, args)))) {
00997                 hudinfo_notify(d, msgclass, "E", "No such target");
00998                 return NULL;
00999         }
01000 
01001         range = FaMechRange(mech, targ);
01002 
01003         if(!InLineOfSight(mech, targ, MechX(targ), MechY(targ), range)) {
01004                 hudinfo_notify(d, msgclass, "E", "No such target");
01005                 return NULL;
01006         }
01007 
01008         if(!MechIsObservator(mech) && (int) range > MechScanRange(mech)) {
01009                 hudinfo_notify(d, msgclass, "E", "Out of range");
01010                 return NULL;
01011         }
01012 
01013         if(MechType(targ) == CLASS_MW ||
01014            !InLineOfSight_NB(mech, targ, MechX(targ), MechY(targ), range)) {
01015                 hudinfo_notify(d, msgclass, "E", "Unable to scan target");
01016                 return NULL;
01017         }
01018 
01019         if(!MechIsObservator(mech)) {
01020                 mech_notify(targ, MECHSTARTED,
01021                                         tprintf("You are being scanned by %s",
01022                                                         GetMechToMechID(targ, mech)));
01023                 auto_reply(targ, tprintf("%s just scanned me.",
01024                                                                  GetMechToMechID(targ, mech)));
01025         }
01026         return targ;
01027 }
01028 
01029 static void hud_armorscan(DESC * d, MECH * mech, char *msgclass, char *args)
01030 {
01031         char response[LBUF_SIZE];
01032         int sect;
01033         MECH *targ;
01034 
01035         targ = hud_scantarget(d, mech, msgclass, args);
01036         if(!targ)
01037                 return;
01038 
01039         for(sect = 0; sect < NUM_SECTIONS; sect++) {
01040                 if(GetSectOInt(targ, sect)) {
01041                         sprintf(response, "%s,%c,%c,%c",
01042                                         ShortArmorSectionString(MechType(targ), MechMove(targ),
01043                                                                                         sect), hud_damagechar(targ, sect,
01044                                                                                                                                   1),
01045                                         hud_damagechar(targ, sect, 4), hud_damagechar(targ, sect,
01046                                                                                                                                   2));
01047                         hudinfo_notify(d, msgclass, "L", response);
01048                 }
01049         }
01050         hudinfo_notify(d, msgclass, "D", "Done");
01051 }
01052 
01053 static char *hud_getweapscanstatus(MECH * mech, int sect, int crit, int data)
01054 {
01055         if(PartIsNonfunctional(mech, sect, crit))
01056                 return "*";
01057         if(data)
01058                 return "-";
01059         return "R";
01060 }
01061 
01062 static void hud_weapscan(DESC * d, MECH * mech, char *msgclass, char *args)
01063 {
01064         int sect, weapcount, i, weapnum = -1;
01065         unsigned char weaparray[MAX_WEAPS_SECTION];
01066         unsigned char weapdata[MAX_WEAPS_SECTION];
01067         int critical[MAX_WEAPS_SECTION];
01068         char response[LBUF_SIZE];
01069         MECH *targ;
01070 
01071         targ = hud_scantarget(d, mech, msgclass, args);
01072         if(!targ)
01073                 return;
01074 
01075         UpdateRecycling(targ);
01076 
01077         for(sect = 0; sect < NUM_SECTIONS; sect++) {
01078                 if(SectIsDestroyed(targ, sect))
01079                         continue;
01080                 weapcount = FindWeapons(targ, sect, weaparray, weapdata, critical);
01081                 if(weapcount <= 0)
01082                         continue;
01083                 for(i = 0; i < weapcount; i++) {
01084                         weapnum++;
01085                         sprintf(response, "%d,%d,%s,%s", weapnum, weaparray[i],
01086                                         ShortArmorSectionString(MechType(targ), MechMove(targ),
01087                                                                                         sect), hud_getweapscanstatus(targ,
01088                                                                                                                                                  sect,
01089                                                                                                                                                  critical
01090                                                                                                                                                  [i],
01091                                                                                                                                                  weapdata
01092                                                                                                                                                  [i] /
01093                                                                                                                                                  WEAPON_TICK));
01094                         hudinfo_notify(d, msgclass, "L", response);
01095                 }
01096         }
01097         hudinfo_notify(d, msgclass, "D", "Done");
01098 }
01099 
01100 static void hud_tactical(DESC * d, MECH * mech, char *msgclass, char *args)
01101 {
01102         MAP *map = getMap(mech->mapindex);
01103         char *argv[5], result[LBUF_SIZE], *p;
01104         char mapid[21], mapname[MBUF_SIZE];
01105         int argc;
01106         int height = 24;
01107         short cx = MechX(mech), cy = MechY(mech);
01108         int sx, sy, ex, ey, x, y, losflag, lostactical = 0;
01109         hexlosmap_info *losmap = NULL;
01110 
01111         if(!MechLRSRange(mech)) {
01112                 hudinfo_notify(d, msgclass, "E",
01113                                            "Your system seems to be inoperational");
01114                 return;
01115         }
01116 
01117         if(!map) {
01118                 hudinfo_notify(d, msgclass, "E", "You are on no map");
01119                 return;
01120         }
01121 
01122         argc = mech_parseattributes(args, argv, 4);
01123 
01124         switch (argc) {
01125         case 4:
01126                 if(strcmp("l", argv[3])) {
01127                         hudinfo_notify(d, msgclass, "E", "Invalid fourth argument");
01128                         return;
01129                 }
01130                 lostactical = 1;
01131                 /* FALLTHROUGH */
01132         case 3:{
01133                         float fx, fy;
01134                         int bearing = atoi(argv[1]);
01135                         float range = atof(argv[2]);
01136 
01137                         if(!MechIsObservator(mech) &&
01138                            abs((int) range) > MechLRSRange(mech)) {
01139                                 hudinfo_notify(d, msgclass, "E", "Out of range");
01140                                 return;
01141                         }
01142                         FindXY(MechFX(mech), MechFY(mech), bearing, range, &fx, &fy);
01143                         RealCoordToMapCoord(&cx, &cy, fx, fy);
01144                 }
01145                 /* FALLTHROUGH */
01146         case 1:
01147                 height = atoi(argv[0]);
01148                 if(!height || height < 0 || height > 40) {
01149                         hudinfo_notify(d, msgclass, "E", "Invalid 1st argument");
01150                         return;
01151                 }
01152                 break;
01153         default:
01154                 hudinfo_notify(d, msgclass, "E", "Invalid arguments");
01155                 return;
01156         }
01157         
01158         if( (cx < 0) || (cx > map->map_width) || (cy > map->map_height) || (cy < 0)) {
01159                 hudinfo_notify(d, msgclass, "E", "Out of range");
01160                 return;
01161         }
01162 
01163         height = MIN(height, 2 * MechLRSRange(mech));
01164         height = MIN(height, map->map_height);
01165 
01166         sy = MAX(0, cy - height / 2);
01167         ey = MIN(map->map_height, cy + height / 2);
01168 
01169         sx = MAX(0, cx - LRS_DISPLAY_WIDTH / 2);
01170         ex = MIN(map->map_width, cx + LRS_DISPLAY_WIDTH / 2);
01171 
01172         if(lostactical || MapIsDark(map) || (MechType(mech) == CLASS_MW &&
01173                                                                                  mudconf.btech_mw_losmap)) {
01174                 /* If height = 1, ey = sy, and ey - sy = 0, which blows up.
01175                  * What we want is empty (no map lines) output, like for the
01176                  * regular tactical map.  A simple way to do that is just not
01177                  * to calculate the LoS map at all.
01178                  *
01179                  * TODO: This should probably be fixed for real somehow.
01180                  */
01181                 if (height > 1) {
01182                         losmap = CalculateLOSMap(map, mech, sx, sy, ex - sx, ey - sy);
01183                 }
01184         }
01185 
01186         if(!mudconf.hudinfo_show_mapinfo ||
01187            (mudconf.hudinfo_show_mapinfo == 1 && In_Character(map->mynum))) {
01188                 strcpy(mapid, "-1");
01189                 strcpy(mapname, "-1");
01190         } else {
01191                 sprintf(mapid, "%d", map->mynum);
01192                 sprintf(mapname, "%s", map->mapname);
01193         };
01194 
01195         sprintf(result, "%d,%d,%d,%d,%s,%s,-1,%d,%d", sx, sy, ex - 1, ey - 1,
01196                         mapid, mapname, map->map_width, map->map_height);
01197         hudinfo_notify(d, msgclass, "S", result);
01198 
01199         for(y = sy; y < ey; y++) {
01200                 sprintf(result, "%d,", y);
01201                 p = result + strlen(result);
01202 
01203                 for(x = sx; x < ex; x++) {
01204                         if(losmap)
01205                                 losflag = LOSMap_GetFlag(losmap, x, y);
01206                         else
01207                                 losflag = MAPLOSHEX_SEE;
01208 
01209                         if(losflag & MAPLOSHEX_SEETERRAIN) {
01210                                 *p = GetTerrain(map, x, y);
01211                                 if(*p == ' ')
01212                                         *p = '.';
01213                                 *p++;
01214                         } else
01215                                 *p++ = '?';
01216 
01217                         if(losflag & MAPLOSHEX_SEEELEV)
01218                                 *p++ = GetElev(map, x, y) + '0';
01219                         else
01220                                 *p++ = '?';
01221                 }
01222                 *p = '\0';
01223                 hudinfo_notify(d, msgclass, "L", result);
01224         }
01225 
01226         hudinfo_notify(d, msgclass, "D", "Done");
01227 }
01228 
01229 static char *hud_getmapflags(MAP * map)
01230 {
01231         static char res[5];
01232         char *p = res;
01233 
01234         if(map->flags & MAPFLAG_VACUUM)
01235                 *p++ = 'V';
01236         if(map->flags & MAPFLAG_UNDERGROUND)
01237                 *p++ = 'U';
01238         if(map->flags & MAPFLAG_DARK)
01239                 *p++ = 'D';
01240 
01241         if(p == res)
01242                 *p++ = '-';
01243 
01244         *p = '\0';
01245         return res;
01246 }
01247 
01248 static void hud_conditions(DESC * d, MECH * mech, char *msgclass, char *args)
01249 {
01250         MAP *map = getMap(mech->mapindex);
01251         char res[200];
01252         char lt;
01253 
01254         switch (map->maplight) {
01255         case 0:
01256                 lt = 'N';
01257                 break;
01258         case 1:
01259                 lt = 'T';
01260                 break;
01261         case 2:
01262                 lt = 'D';
01263                 break;
01264         default:
01265                 lt = '?';
01266                 SendError(tprintf("Unknown light type %d on map #%d",
01267                                                   map->maplight, map->mynum));
01268                 break;
01269         }
01270 
01271         sprintf(res, "%c,%d,%d,%d,%s", lt, map->mapvis, map->grav,
01272                         map->temp, hud_getmapflags(map));
01273         hudinfo_notify(d, msgclass, "R", res);
01274 }
01275 
01276 #endif

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