00001
00002
00003
00004
00005
00006
00007
00008
00009
00010 #include <stdio.h>
00011 #include <stdlib.h>
00012 #include <math.h>
00013 #include <sys/file.h>
00014
00015 #include "mech.h"
00016 #include "mech.events.h"
00017 #include "map.h"
00018 #include "p.mech.utils.h"
00019 #include "p.mech.los.h"
00020
00021 char *default_contactoptions = "!db";
00022
00023 static char *ac_desc[] = {
00024 "0 - See enemies and friends, long text, color",
00025 "1 - See enemies and friends, short text, color",
00026 "2 - See enemies only, long text, color",
00027 "3 - See enemies only, short text, color",
00028 "4 - See enemies and friends, short text, no color",
00029 "5 - See enemies only, short text, no color",
00030
00031 "6 - Disabled"
00032 };
00033
00034 static char *c_desc[] = {
00035 "0 - Very verbose",
00036 "1 - Short form, the usual one",
00037 "2 - Short form, the usual one, but do not see buildings",
00038 "3 - Shorter form"
00039 };
00040
00041 void show_brief_flags(dbref player, MECH * mech)
00042 {
00043 notify_printf(player, "Brief status for %s:", GetMechToMechID(mech,
00044 mech));
00045 #ifdef ADVANCED_LOS
00046 notify_printf(player, " (A)utocontacts: %s", ac_desc[mech->brief / 4]);
00047 #endif
00048 notify_printf(player, " (C)ontacts: %s", c_desc[mech->brief % 4]);
00049 }
00050
00051 void mech_brief(dbref player, void *data, char *buffer)
00052 {
00053 MECH *mech = (MECH *) data;
00054 char c;
00055 int v;
00056
00057 cch(MECH_USUALSM);
00058 skipws(buffer);
00059 if(!*buffer) {
00060 show_brief_flags(player, mech);
00061 return;
00062 }
00063 c = *buffer;
00064 buffer++;
00065 skipws(buffer);
00066 DOCHECK(!*buffer, "Argument missing!");
00067 DOCHECK(Readnum(v, buffer), "Invalid number!");
00068 switch (toupper(c)) {
00069 #ifdef ADVANCED_LOS
00070 case 'A':
00071 DOCHECK(v < 0 || v > 6, "Number out of range!");
00072 v = BOUNDED(0, v, 6);
00073 mech->brief = mech->brief % 4;
00074 mech->brief += v * 4;
00075 mech_printf(mech, MECHALL,
00076 "Autocontact brevity set to %s.", ac_desc[v]);
00077 return;
00078 #endif
00079 case 'C':
00080 DOCHECK(v < 0 || v > 3, "Number out of range!");
00081 v = BOUNDED(0, v, 3);
00082 mech->brief = ((mech->brief / 4) * 4) + v;
00083 mech_printf(mech, MECHALL, "Contact brevity set to %s.", c_desc[v]);
00084 return;
00085 }
00086 }
00087
00088 #define SEE_DEAD 0x01
00089 #define SEE_SHUTDOWN 0x02
00090 #define SEE_ALLY 0x04
00091 #define SEE_ENEMA 0x08
00092 #define SEE_TARGET 0x10
00093 #define SEE_BUILDINGS 0x20
00094 #define SEE_NEGNEXT 0x80
00095
00096 char getWeaponArc(MECH * mech, int arc)
00097 {
00098 if(arc & FORWARDARC)
00099 return '*';
00100 else if(arc & TURRETARC)
00101 return 't';
00102 else if(arc & RSIDEARC)
00103 return 'r';
00104 else if(arc & LSIDEARC)
00105 return 'l';
00106 else if(arc & REARARC)
00107 return 'v';
00108 else
00109 return '?';
00110 }
00111
00112
00113 char *getStatusString(MECH * target, int who)
00114 {
00115 static char statusstr[20];
00116 int sptr = 0;
00117
00118 if(Destroyed(target))
00119 statusstr[sptr++] = 'D';
00120
00121 if(Starting(target))
00122 statusstr[sptr++] = 's';
00123 else if(!Started(target))
00124 statusstr[sptr++] = 'S';
00125
00126 if(Standing(target))
00127 statusstr[sptr++] = 'f';
00128 else if(Fallen(target))
00129 statusstr[sptr++] = 'F';
00130
00131 if(ChangingHulldown(target))
00132 statusstr[sptr++] = 'h';
00133 else if(IsHulldown(target))
00134 statusstr[sptr++] = 'H';
00135
00136 if(Towed(target))
00137 statusstr[sptr++] = 'T';
00138 else if(MechCarrying(target) > 0)
00139 statusstr[sptr++] = 't';
00140
00141 if(Jumping(target))
00142 statusstr[sptr++] = 'J';
00143
00144 if(OODing(target))
00145 statusstr[sptr++] = 'O';
00146
00147 if(MechHeat(target))
00148 statusstr[sptr++] = '+';
00149
00150 if(Jellied(target))
00151 statusstr[sptr++] = 'I';
00152
00153 if(Burning(target))
00154 statusstr[sptr++] = 'B';
00155
00156 if(MechLites(target))
00157 statusstr[sptr++] = 'L';
00158
00159 if(MechLit(target))
00160 statusstr[sptr++] = 'l';
00161
00162 if(MechSwarmTarget(target) > 0)
00163 statusstr[sptr++] = 'W';
00164
00165 if(CarryingClub(target))
00166 statusstr[sptr++] = 'C';
00167
00168 if(checkAllSections(target, NARC_ATTACHED) ||
00169 checkAllSections(target, INARC_HOMING_ATTACHED)) {
00170 if(who == 1)
00171 statusstr[sptr++] = 'N';
00172 else
00173 statusstr[sptr++] = 'n';
00174 }
00175 #ifndef ECM_ON_CONTACTS
00176 if(who > 1) {
00177 #endif
00178 if(AnyECCMActive(target))
00179 statusstr[sptr++] = 'P';
00180
00181 if(AnyECMActive(target))
00182 statusstr[sptr++] = 'E';
00183
00184 if(AnyECMProtected(target))
00185 statusstr[sptr++] = 'p';
00186
00187 if(AnyECMDisturbed(target))
00188 statusstr[sptr++] = 'e';
00189 #ifndef ECM_ON_CONTACTS
00190 }
00191 #endif
00192
00193 if(Spinning(target))
00194 statusstr[sptr++] = 'X';
00195
00196 #ifdef BT_MOVEMENT_MODES
00197 if(Sprinting(target))
00198 statusstr[sptr++] = 'M';
00199 if(Evading(target))
00200 statusstr[sptr++] = 'm';
00201 #endif
00202
00203 statusstr[sptr] = '\0';
00204 return statusstr;
00205 }
00206
00207 char getStatusChar(MECH * mech, MECH * mechTarget, int wCharNum)
00208 {
00209 char cRet = ' ';
00210
00211 switch (wCharNum) {
00212 case 1:
00213 cRet = MechSwarmTarget(mechTarget) > 0 ? 'W' :
00214 Towed(mechTarget) ? 'T' : MechCarrying(mechTarget) >
00215 0 ? 't' : CarryingClub(mechTarget) ? 'C' :
00216 #ifdef BT_MOVEMENT_MODES
00217 Sprinting(mechTarget) ? 'M' : Evading(mechTarget) ? 'm' :
00218 #endif
00219 ' ';
00220 break;
00221 case 2:
00222 cRet = Destroyed(mechTarget) ? 'D' :
00223 MechLites(mechTarget) ? 'L' : MechLit(mechTarget) ? 'l' : ' ';
00224 break;
00225 case 3:
00226 cRet = Jumping(mechTarget) ? 'J' : OODing(mechTarget) ? 'O' :
00227 Fallen(mechTarget) ? 'F' : Standing(mechTarget) ? 'f' :
00228 ChangingHulldown(mechTarget) ? 'h' : IsHulldown(mechTarget) ?
00229 'H' : Spinning(mech) ? 'X' : ' ';
00230 break;
00231 case 4:
00232 cRet = Started(mechTarget) ?
00233 (MechHeat(mechTarget) ? '+' :
00234 Jellied(mechTarget) ? 'I' :
00235 Burning(mechTarget) ? 'B' : ' ') :
00236 Staggering(mechTarget) ? 'G' : Starting(mechTarget) ? 's' : 'S';
00237 break;
00238 case 5:
00239 cRet = (checkAllSections(mechTarget, NARC_ATTACHED) ||
00240 checkAllSections(mechTarget, INARC_HOMING_ATTACHED)) ?
00241 (MechTeam(mechTarget) == MechTeam(mech) ? 'n' : 'N') :
00242 #ifdef ECM_ON_CONTACTS
00243 AnyECCMActive(mechTarget) ? 'P' :
00244 AnyECMActive(mechTarget) ? 'E' :
00245 AnyECMProtected(mechTarget) ? 'p' :
00246 AnyECMDisturbed(mechTarget) ? 'e' :
00247 #endif
00248 ' ';
00249 break;
00250 }
00251
00252 return cRet;
00253 }
00254
00255 void mech_contacts(dbref player, void *data, char *buffer)
00256 {
00257 MECH *mech = (MECH *) data, *tempMech;
00258 MAP *mech_map = getMap(mech->mapindex), *tmp_map;
00259 mapobj *building;
00260 int loop, i, j, argc, bearing, buffindex = 0;
00261 char *args[1], bufflist[MAX_MECHS_PER_MAP][120], buff[100];
00262 int sbuff[MAX_MECHS_PER_MAP];
00263 float range, rangelist[MAX_MECHS_PER_MAP], fx, fy;
00264 int mechfound;
00265 char weaponarc;
00266 char *mech_name;
00267 char see_what;
00268 char *str;
00269 char move_type[30];
00270 char cStatus1, cStatus2, cStatus3, cStatus4, cStatus5;
00271 int losflag;
00272 int isvb;
00273 int inlos;
00274 int IsUsingHUD = 0;
00275 char new[LBUF_SIZE];
00276
00277 cch(MECH_USUAL);
00278 mechfound = 0;
00279 argc = mech_parseattributes(buffer, args, 1);
00280
00281 isvb = (mech->brief % 4);
00282 if(argc > 0) {
00283 if(args[0][0] == 'h') {
00284 IsUsingHUD = 1;
00285 see_what =
00286 (SEE_DEAD | SEE_SHUTDOWN | SEE_ENEMA | SEE_ALLY | SEE_TARGET);
00287 } else {
00288 if(args[0][0] == '+') {
00289 str = silly_atr_get(player, A_CONTACTOPT);
00290 if(!*str)
00291 strcpy(buff, default_contactoptions);
00292 else {
00293 strncpy(buff, str, 50);
00294 buff[49] = 0;
00295
00296 if(strlen(buff) == 0)
00297 strcpy(buff, default_contactoptions);
00298 }
00299 } else {
00300 strncpy(buff, args[0], 50);
00301 buff[49] = 0;
00302 }
00303
00304 if(isvb == 1)
00305 see_what = SEE_BUILDINGS;
00306 else
00307 see_what = 0x0;
00308
00309 for(loop = 0; loop < 50 && buff[loop]; loop++) {
00310 char c;
00311
00312 c = buff[loop];
00313
00314 if(c == 'd')
00315
00316 (see_what & SEE_NEGNEXT) ? (see_what &=
00317 ~SEE_DEAD) : (see_what |=
00318 SEE_DEAD);
00319 else if(c == 's')
00320 (see_what & SEE_NEGNEXT) ? (see_what &=
00321 ~SEE_SHUTDOWN) : (see_what |=
00322 SEE_SHUTDOWN);
00323 else if(c == 'b')
00324 (see_what & SEE_NEGNEXT) ? (see_what &=
00325 ~SEE_BUILDINGS) : (see_what |=
00326 SEE_BUILDINGS);
00327 else if(c == 'e')
00328 (see_what & SEE_NEGNEXT) ? (see_what &=
00329 ~SEE_ENEMA) : (see_what |=
00330 SEE_ENEMA);
00331 else if(c == 'a')
00332 (see_what & SEE_NEGNEXT) ? (see_what &=
00333 ~SEE_ALLY) : (see_what |=
00334 SEE_ALLY);
00335 else if(c == 't')
00336 (see_what & SEE_NEGNEXT) ? (see_what &=
00337 ~SEE_TARGET) : (see_what |=
00338 SEE_TARGET);
00339 else if(c == '!') {
00340 see_what =
00341 (SEE_NEGNEXT | SEE_DEAD | SEE_SHUTDOWN | SEE_ENEMA
00342 | SEE_ALLY | SEE_TARGET);
00343 } else
00344 notify_printf(player,
00345 "Ignoring %c as contact option.", c);
00346 }
00347 }
00348 } else {
00349 see_what =
00350 (SEE_DEAD | SEE_SHUTDOWN | SEE_ENEMA | SEE_ALLY | SEE_TARGET);
00351 if(isvb == 1)
00352 see_what |= SEE_BUILDINGS;
00353 }
00354
00355 if(IsUsingHUD)
00356 notify(player, "#HUDINFO:CON#Line of Sight Contacts:");
00357 else if(isvb <= 2)
00358 notify(player, "Line of Sight Contacts:");
00359
00360 for(loop = 0; loop < mech_map->first_free; loop++) {
00361 if(!(mech_map->mechsOnMap[loop] != mech->mynum &&
00362 mech_map->mechsOnMap[loop] != -1))
00363 continue;
00364
00365 tempMech = (MECH *) FindObjectsData(mech_map->mechsOnMap[loop]);
00366
00367 if(!tempMech)
00368 continue;
00369 if(argc) {
00370 if(!((MechSeemsFriend(mech, tempMech) ? (see_what & SEE_ALLY)
00371 : (see_what & SEE_ENEMA)) ||
00372 ((see_what & SEE_TARGET) &&
00373 (tempMech->mynum == MechTarget(mech)))))
00374 continue;
00375 if(!(((see_what & SEE_SHUTDOWN) || Started(tempMech)) ||
00376 Destroyed(tempMech) || ((see_what & SEE_TARGET) &&
00377 (tempMech->mynum ==
00378 MechTarget(mech)))))
00379 continue;
00380 if(!(((see_what & SEE_DEAD) || !Destroyed(tempMech)) ||
00381 ((see_what & SEE_TARGET) &&
00382 (tempMech->mynum == MechTarget(mech)))))
00383 continue;
00384 }
00385 range = FlMechRange(mech_map, mech, tempMech);
00386 if(!(losflag =
00387 InLineOfSight(mech, tempMech, MechX(tempMech),
00388 MechY(tempMech), range)))
00389 continue;
00390 if(Good_obj(tempMech->mynum)) {
00391 if(!InLineOfSight_NB(mech, tempMech, MechX(tempMech),
00392 MechY(tempMech), 0.0)) {
00393 mech_name = "something";
00394 inlos = 0;
00395 } else {
00396 mech_name = silly_atr_get(tempMech->mynum, A_MECHNAME);
00397 inlos = 1;
00398 }
00399 } else
00400 continue;
00401 bearing =
00402 FindBearing(MechFX(mech), MechFY(mech), MechFX(tempMech),
00403 MechFY(tempMech));
00404 weaponarc = getWeaponArc(mech, InWeaponArc(mech, MechFX(tempMech),
00405 MechFY(tempMech)));
00406
00407 strcpy(move_type, GetMoveTypeID(MechMove(tempMech)));
00408
00409 if(isvb) {
00410 if(!inlos) {
00411 cStatus1 = ' ';
00412 cStatus2 = ' ';
00413 cStatus3 = ' ';
00414 cStatus4 = ' ';
00415 cStatus5 = ' ';
00416 } else {
00417 cStatus1 = getStatusChar(mech, tempMech, 1);
00418 cStatus2 = getStatusChar(mech, tempMech, 2);
00419 cStatus3 = getStatusChar(mech, tempMech, 3);
00420 cStatus4 = getStatusChar(mech, tempMech, 4);
00421 cStatus5 = getStatusChar(mech, tempMech, 5);
00422 }
00423
00424 if(!IsUsingHUD) {
00425 sprintf(buff,
00426 "%s%c%c%c[%s]%c %-12.12s x:%3d y:%3d z:%3d r:%4.1f b:%3d s:%5.1f h:%3d S:%c%c%c%c%c%s",
00427 tempMech->mynum == MechTarget(mech) ? "%ch%cr" :
00428 !MechSeemsFriend(mech, tempMech) ? "%ch%cy" : "",
00429 (losflag & MECHLOSFLAG_SEESP) ? 'P' : ' ',
00430 (losflag & MECHLOSFLAG_SEESS) ? 'S' : ' ',
00431 weaponarc, MechIDS(tempMech,
00432 MechSeemsFriend(mech, tempMech)),
00433 move_type[0], mech_name, MechX(tempMech),
00434 MechY(tempMech), MechZ(tempMech), range, bearing,
00435 MechSpeed(tempMech), MechVFacing(tempMech),
00436 cStatus1,
00437 cStatus2,
00438 cStatus3,
00439 cStatus4,
00440 cStatus5,
00441 (tempMech->mynum == MechTarget(mech) ||
00442 !MechSeemsFriend(mech, tempMech)) ? "%c" : "");
00443 } else {
00444 sprintf(buff,
00445 "#HUDINFO:CON#%c,%c,%c,%c,%s,%c,%-12.12s,%3d,%3d,%3d,%4.1f,%3d,%4.1f,%3d,%c%c%c%c%c",
00446 (tempMech->mynum == MechTarget(mech)) ? 'T' :
00447 !MechSeemsFriend(mech, tempMech) ? 'E' : 'F',
00448 (losflag & MECHLOSFLAG_SEESP) ? 'P' : ' ',
00449 (losflag & MECHLOSFLAG_SEESS) ? 'S' : ' ',
00450 weaponarc, MechIDS(tempMech,
00451 MechSeemsFriend(mech, tempMech)),
00452 move_type[0], mech_name, MechX(tempMech),
00453 MechY(tempMech), MechZ(tempMech), range, bearing,
00454 MechSpeed(tempMech), MechVFacing(tempMech),
00455 cStatus1, cStatus2, cStatus3, cStatus4, cStatus5);
00456 }
00457
00458 rangelist[buffindex] = range;
00459 rangelist[buffindex] +=
00460 (MechStatus(tempMech) & DESTROYED) ? 10000 : 0;
00461 strcpy(bufflist[buffindex++], buff);
00462 } else {
00463 sprintf(buff, "[%s] %-17s Tonnage: %d", MechIDS(tempMech,
00464 MechSeemsFriend
00465 (mech,
00466 tempMech)),
00467 mech_name, MechTons(tempMech));
00468 notify(player, buff);
00469 sprintf(buff, " Range: %.1f hex\tBearing: %d degrees",
00470 range, bearing);
00471 notify(player, buff);
00472 sprintf(buff, " Speed: %.1f KPH\tHeading: %d degrees",
00473 MechSpeed(tempMech), MechVFacing(tempMech));
00474 notify(player, buff);
00475 sprintf(buff, " X, Y: %3d, %3d \tHeat: %.0f deg C.",
00476 MechX(tempMech), MechY(tempMech), MechHeat(tempMech));
00477 notify(player, buff);
00478 sprintf(buff, " Movement Type: %s", move_type);
00479 notify(player, buff);
00480 notify_printf(player, " Mech is in %s Arc",
00481 GetArcID(mech, InWeaponArc(mech, MechFX(tempMech),
00482 MechFY(tempMech))));
00483 if(MechStatus(tempMech) & DESTROYED)
00484 notify(player, " Mech Destroyed");
00485 if(!(MechStatus(tempMech) & STARTED))
00486 notify(player, " Mech Shutdown");
00487 if(Fallen(tempMech))
00488 notify(player, " Mech has Fallen!");
00489 if(Jumping(tempMech))
00490 notify_printf(player,
00491 " Mech is Jumping!\tJump Heading: %d",
00492 MechJumpHeading(tempMech));
00493 notify(player, " ");
00494 }
00495 }
00496
00497 if(see_what & SEE_BUILDINGS) {
00498 for(building = first_mapobj(mech_map, TYPE_BUILD); building;
00499 building = next_mapobj(building)) {
00500
00501 MapCoordToRealCoord(building->x, building->y, &fx, &fy);
00502 range =
00503 FindRange(MechFX(mech), MechFY(mech), MechFZ(mech), fx, fy,
00504 ZSCALE * ((i =
00505 Elevation(mech_map, building->x,
00506 building->y)) + 1));
00507
00508 losflag =
00509 InLineOfSight(mech, NULL, building->x, building->y, range);
00510 if(!losflag || (losflag & MECHLOSFLAG_BLOCK))
00511 continue;
00512
00513 if(!(building->obj && (tmp_map = getMap(building->obj))))
00514 continue;
00515 if(BuildIsInvis(tmp_map))
00516 continue;
00517 if((j = !can_pass_lock(mech->mynum, tmp_map->mynum, A_LENTER))
00518 && BuildIsHidden(tmp_map))
00519 continue;
00520 bearing = FindBearing(MechFX(mech), MechFY(mech), fx, fy);
00521 weaponarc = getWeaponArc(mech, InWeaponArc(mech, fx, fy));
00522
00523 mech_name = silly_atr_get(building->obj, A_MECHNAME);
00524 if(!mech_name || !*mech_name) {
00525 strncpy(new, Name(building->obj), LBUF_SIZE-1);
00526 mech_name = strip_ansi_r(new,Name(building->obj),strlen(Name(building->obj)));
00527 }
00528
00529 if(!IsUsingHUD) {
00530 sprintf(buff,
00531 "%s%c%c%c %-23.23s x:%3d y:%3d z:%2d r:%4.1f b:%3d CF:%4d /%4d S:%c%c%s",
00532 j ? "%ch%cy" : "",
00533 (losflag & MECHLOSFLAG_SEESP) ? 'P' : ' ',
00534 (losflag & MECHLOSFLAG_SEESS) ? 'S' : ' ',
00535 weaponarc, mech_name, building->x, building->y, i,
00536 range, bearing, tmp_map->cf, tmp_map->cfmax,
00537 (BuildIsSafe(tmp_map) || (j &&
00538 BuildIsCS(tmp_map))) ? 'X' :
00539 j ? 'x' : BuildIsCS(tmp_map) ? 'C' : ' ',
00540 BuildIsHidden(tmp_map) ? 'H' : ' ', j ? "%c" : "");
00541 } else {
00542 sprintf(buff,
00543 "#HUDINFO:CON#%c,%c,%c,%c,%-21.21s,%3d,%3d,%3d,%4.1f,%3d,%4d,%4d,%c%c",
00544 j ? 'E' : 'F',
00545 (losflag & MECHLOSFLAG_SEESP) ? 'P' : ' ',
00546 (losflag & MECHLOSFLAG_SEESS) ? 'S' : ' ',
00547 weaponarc, mech_name, building->x, building->y, i,
00548 range, bearing, tmp_map->cf, tmp_map->cfmax,
00549 (BuildIsSafe(tmp_map) || (j &&
00550 BuildIsCS(tmp_map))) ? 'X' :
00551 j ? 'x' : BuildIsCS(tmp_map) ? 'C' : ' ',
00552 BuildIsHidden(tmp_map) ? 'H' : ' ');
00553 }
00554 rangelist[buffindex] = range + 20000;
00555 strcpy(bufflist[buffindex++], buff);
00556 }
00557 }
00558
00559 if(isvb) {
00560 for(i = 0; i < buffindex; i++)
00561 sbuff[i] = i;
00562
00563
00564 for(i = 0; i < (buffindex - 1); i++)
00565 for(j = (i + 1); j < buffindex; j++)
00566 if(rangelist[sbuff[j]] > rangelist[sbuff[i]]) {
00567 loop = sbuff[i];
00568 sbuff[i] = sbuff[j];
00569 sbuff[j] = loop;
00570 }
00571 for(loop = 0; loop < buffindex; loop++)
00572 notify(player, bufflist[sbuff[loop]]);
00573 }
00574
00575 if(IsUsingHUD)
00576 notify(player, "#HUDINFO:CON#End Contact List");
00577 else if(isvb <= 2)
00578 notify(player, "End Contact List");
00579 }
00580
00581 #undef SEE_DEAD
00582 #undef SEE_SHUTDOWN
00583 #undef SEE_ALLY
00584 #undef SEE_ENEMA
00585 #undef SEE_TARGET
00586 #undef SEE_BUILDINGS
00587 #undef SEE_NEGNEXT