00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018 #include <math.h>
00019
00020 #include "mech.h"
00021 #include "artillery.h"
00022 #include "mech.events.h"
00023 #include "create.h"
00024 #include "p.artillery.h"
00025 #include "p.mech.fire.h"
00026 #include "p.mech.combat.h"
00027 #include "p.mech.combat.misc.h"
00028 #include "p.mech.damage.h"
00029 #include "p.mech.utils.h"
00030 #include "p.map.obj.h"
00031 #include "p.mech.hitloc.h"
00032 #include "p.mine.h"
00033 #include "spath.h"
00034
00035 struct artillery_shot_type *free_shot_list = NULL;
00036 static void artillery_hit(artillery_shot * s);
00037
00038 static const char *artillery_type(artillery_shot * s)
00039 {
00040 if(s->type == CL_ARROW || s->type == IS_ARROW)
00041 return "a missile";
00042 return "a round";
00043 }
00044
00045 static struct {
00046 int dir;
00047 char *desc;
00048 } arty_dirs[] = {
00049 {
00050 0, "north"}, {
00051 60, "northeast"}, {
00052 90, "east"}, {
00053 120, "southeast"}, {
00054 180, "south"}, {
00055 240, "southwest"}, {
00056 270, "west"}, {
00057 300, "northwest"}, {
00058 0, NULL}
00059 };
00060
00061 static const char *artillery_direction(artillery_shot * s)
00062 {
00063 float fx, fy, tx, ty;
00064 int b, d, i, best = -1, bestd = 0;
00065
00066 MapCoordToRealCoord(s->from_x, s->from_y, &fx, &fy);
00067 MapCoordToRealCoord(s->to_x, s->to_y, &tx, &ty);
00068 b = FindBearing(fx, fy, tx, ty);
00069 for(i = 0; arty_dirs[i].desc; i++) {
00070 d = abs(b - arty_dirs[i].dir);
00071 if(best < 0 || d < bestd) {
00072 best = i;
00073 bestd = d;
00074 }
00075 }
00076 if(best < 0)
00077 return "Invalid";
00078 return arty_dirs[best].desc;
00079 }
00080
00081 int artillery_round_flight_time(float fx, float fy, float tx, float ty)
00082 {
00083 int delay = MAX(ARTILLERY_MINIMUM_FLIGHT,
00084 (FindHexRange(fx, fy, tx, ty) / ARTY_SPEED));
00085
00086
00087 return delay;
00088 }
00089
00090 static void artillery_hit_event(MUXEVENT * e)
00091 {
00092 artillery_shot *s = (artillery_shot *) e->data;
00093
00094 artillery_hit(s);
00095 ADD_TO_LIST_HEAD(free_shot_list, next, s);
00096 }
00097
00098 void artillery_shoot(MECH * mech, int targx, int targy, int windex,
00099 int wmode, int ishit)
00100 {
00101 struct artillery_shot_type *s;
00102 float fx, fy, tx, ty;
00103
00104 if(free_shot_list) {
00105 s = free_shot_list;
00106 free_shot_list = free_shot_list->next;
00107 } else
00108 Create(s, artillery_shot, 1);
00109 s->from_x = MechX(mech);
00110 s->from_y = MechY(mech);
00111 s->to_x = targx;
00112 s->to_y = targy;
00113 s->type = windex;
00114 s->mode = wmode;
00115 s->ishit = ishit;
00116 s->shooter = mech->mynum;
00117 s->map = mech->mapindex;
00118 MechLOSBroadcast(mech, tprintf("shoots %s towards %s!",
00119 artillery_type(s),
00120 artillery_direction(s)));
00121 MapCoordToRealCoord(s->from_x, s->from_y, &fx, &fy);
00122 MapCoordToRealCoord(s->to_x, s->to_y, &tx, &ty);
00123 muxevent_add(artillery_round_flight_time(fx, fy, tx, ty), 0, EVENT_DHIT,
00124 artillery_hit_event, (void *) s, NULL);
00125 }
00126
00127 static int blast_arcf(float fx, float fy, MECH * mech)
00128 {
00129 int b, dir;
00130
00131 b = FindBearing(MechFX(mech), MechFY(mech), fx, fy);
00132 dir = AcceptableDegree(b - MechFacing(mech));
00133 if(dir > 120 && dir < 240)
00134 return BACK;
00135 if(dir > 300 || dir < 60)
00136 return FRONT;
00137 if(dir > 180)
00138 return LEFTSIDE;
00139 return RIGHTSIDE;
00140 }
00141
00142 #define TABLE_GEN 0
00143 #define TABLE_PUNCH 1
00144 #define TABLE_KICK 2
00145
00146 void blast_hit_hexf(MAP * map, int dam, int singlehitsize, int heatdam,
00147 float fx, float fy, float tfx, float tfy, char *tomsg,
00148 char *otmsg, int table, int safeup, int safedown,
00149 int isunderwater)
00150 {
00151 MECH *tempMech;
00152 int loop;
00153 int isrear = 0, iscritical = 0, hitloc;
00154 int damleft, arc, ndam;
00155 int ground_zero;
00156 short tx, ty;
00157
00158
00159 if(!map)
00160 return;
00161
00162 RealCoordToMapCoord(&tx, &ty, fx, fy);
00163 if(tx < 0 || ty < 0 || tx >= map->map_width || ty >= map->map_height)
00164 return;
00165 if(!tomsg || !otmsg)
00166 return;
00167 if(isunderwater)
00168 ground_zero = Elevation(map, tx, ty);
00169 else
00170 ground_zero = MAX(0, Elevation(map, tx, ty));
00171
00172 for(loop = 0; loop < map->first_free; loop++)
00173 if(map->mechsOnMap[loop] >= 0) {
00174 tempMech = (MECH *)
00175 FindObjectsData(map->mechsOnMap[loop]);
00176 if(!tempMech)
00177 continue;
00178 if(MechX(tempMech) != tx || MechY(tempMech) != ty)
00179 continue;
00180
00181 if(MechZ(tempMech) >= (safeup + ground_zero))
00182 continue;
00183
00184 if(
00185 MechZ(tempMech) <= (ground_zero - safedown))
00186 continue;
00187 MechLOSBroadcast(tempMech, otmsg);
00188 mech_notify(tempMech, MECHALL, tomsg);
00189 arc = blast_arcf(tfx, tfy, tempMech);
00190
00191 if(arc == BACK)
00192 isrear = 1;
00193 damleft = dam;
00194
00195 while (damleft > 0) {
00196 if(singlehitsize <= damleft)
00197 ndam = singlehitsize;
00198 else
00199 ndam = damleft;
00200
00201 damleft -= ndam;
00202
00203 switch (table) {
00204 case TABLE_PUNCH:
00205 if (MechType(tempMech) != CLASS_MECH) {
00206 hitloc = FindHitLocation(tempMech, arc, &iscritical, &isrear);
00207 } else {
00208 hitloc = FindPunchLocation(tempMech, arc);
00209 }
00210 break;
00211 case TABLE_KICK:
00212 if (MechType(tempMech) != CLASS_MECH) {
00213 hitloc = FindHitLocation(tempMech, arc, &iscritical, &isrear);
00214 } else {
00215 hitloc = FindKickLocation(tempMech, arc);
00216 }
00217 break;
00218 default:
00219 hitloc =
00220 FindHitLocation(tempMech, arc, &iscritical, &isrear);
00221 }
00222
00223 DamageMech(tempMech, tempMech, 0, -1, hitloc, isrear,
00224 iscritical, ndam, 0, -1, 0, -1, 0, 0);
00225 }
00226 heat_effect(NULL, tempMech, heatdam, 0);
00227 }
00228 }
00229
00230 void blast_hit_hex(MAP * map, int dam, int singlehitsize, int heatdam,
00231 int fx, int fy, int tx, int ty, char *tomsg, char *otmsg,
00232 int table, int safeup, int safedown, int isunderwater)
00233 {
00234 float ftx, fty;
00235 float ffx, ffy;
00236
00237 MapCoordToRealCoord(tx, ty, &ftx, &fty);
00238 MapCoordToRealCoord(fx, fy, &ffx, &ffy);
00239 blast_hit_hexf(map, dam, singlehitsize, heatdam, ffx, ffy, ftx, fty,
00240 tomsg, otmsg, table, safeup, safedown, isunderwater);
00241 }
00242
00243 void blast_hit_hexesf(MAP * map, int dam, int singlehitsize, int heatdam,
00244 float fx, float fy, float ftx, float fty, char *tomsg,
00245 char *otmsg, char *tomsg1, char *otmsg1, int table,
00246 int safeup, int safedown, int isunderwater,
00247 int doneighbors)
00248 {
00249 int x1, y1, x2, y2;
00250 int dm;
00251 short tx, ty;
00252 float hx, hy;
00253 float t = FindXYRange(fx, fy, ftx, fty);
00254
00255 dm = MAX(1, (int) t + 1);
00256 blast_hit_hexf(map, dam / dm, singlehitsize, heatdam / dm, fx, fy, ftx,
00257 fty, tomsg, otmsg, table, safeup, safedown, isunderwater);
00258 if(!doneighbors)
00259 return;
00260 RealCoordToMapCoord(&tx, &ty, fx, fy);
00261 for(x1 = (tx - doneighbors); x1 <= (tx + doneighbors); x1++)
00262 for(y1 = (ty - doneighbors); y1 <= (ty + doneighbors); y1++) {
00263 int spot;
00264
00265 if((dm = MyHexDist(tx, ty, x1, y1, 0)) > doneighbors)
00266 continue;
00267 if((tx == x1) && (ty == y1))
00268 continue;
00269 x2 = BOUNDED(0, x1, map->map_width - 1);
00270 y2 = BOUNDED(0, y1, map->map_height - 1);
00271 if(x1 != x2 || y1 != y2)
00272 continue;
00273 spot = (x1 == tx && y1 == ty);
00274 MapCoordToRealCoord(x1, y1, &hx, &hy);
00275 dm++;
00276 if(!(dam / dm))
00277 continue;
00278 blast_hit_hexf(map, dam / dm, singlehitsize, heatdam / dm, hx,
00279 hy, ftx, fty, spot ? tomsg : tomsg1,
00280 spot ? otmsg : otmsg1, table, safeup, safedown,
00281 isunderwater);
00282
00283
00284
00285
00286
00287
00288
00289
00290 switch (GetRTerrain(map, x1, y1)) {
00291 case LIGHT_FOREST:
00292 case HEAVY_FOREST:
00293 if(!find_decorations(map, x1, y1)) {
00294 add_decoration(map, x1, y1, TYPE_FIRE, FIRE,
00295 FIRE_DURATION);
00296 }
00297
00298 break;
00299 }
00300 }
00301 }
00302
00303 void blast_hit_hexes(MAP * map, int dam, int singlehitsize, int heatdam,
00304 int tx, int ty, char *tomsg, char *otmsg, char *tomsg1,
00305 char *otmsg1, int table, int safeup, int safedown,
00306 int isunderwater, int doneighbors)
00307 {
00308 float fx, fy;
00309
00310 MapCoordToRealCoord(tx, ty, &fx, &fy);
00311 blast_hit_hexesf(map, dam, singlehitsize, heatdam, fx, fy, fx, fy,
00312 tomsg, otmsg, tomsg1, otmsg1, table, safeup, safedown,
00313 isunderwater, doneighbors);
00314 }
00315
00316 static void artillery_hit_hex(MAP * map, artillery_shot * s, int type,
00317 int mode, int dam, int tx, int ty, int isdirect)
00318 {
00319 char buf[LBUF_SIZE];
00320 char buf1[LBUF_SIZE];
00321 char buf2[LBUF_SIZE];
00322
00323
00324 if(tx < 0 || tx >= map->map_width || ty < 0 || ty >= map->map_height)
00325 return;
00326
00327 if((mode & SMOKE_MODE)) {
00328
00329 add_decoration(map, tx, ty, TYPE_SMOKE, SMOKE, SMOKE_DURATION);
00330 return;
00331 }
00332 if(mode & MINE_MODE) {
00333 add_mine(map, tx, ty, dam);
00334 return;
00335 }
00336 if(!(mode & CLUSTER_MODE)) {
00337 if(isdirect)
00338 sprintf(buf1, "receives a direct hit!");
00339 else
00340 sprintf(buf1, "is hit by fragments!");
00341 if(isdirect)
00342 sprintf(buf2, "You receive a direct hit!");
00343 else
00344 sprintf(buf2, "You are hit by fragments!");
00345 } else {
00346 if(dam > 2)
00347 strcpy(buf, "bomblets");
00348 else
00349 strcpy(buf, "a bomblet");
00350 sprintf(buf1, "is hit by %s!", buf);
00351 sprintf(buf2, "You are hit by %s!", buf);
00352 }
00353 blast_hit_hex(map, dam, (mode & CLUSTER_MODE) ? 2 : 5, 0, tx, ty, tx,
00354 ty, buf2, buf1,
00355 (mode & CLUSTER_MODE) ? TABLE_PUNCH : TABLE_GEN, 10, 4, 0);
00356 }
00357
00358 static artillery_shot *hit_neighbors_s;
00359 static int hit_neighbors_type;
00360 static int hit_neighbors_mode;
00361 static int hit_neighbors_dam;
00362
00363 static void artillery_hit_neighbors_callback(MAP * map, int x, int y)
00364 {
00365 artillery_hit_hex(map, hit_neighbors_s, hit_neighbors_type,
00366 hit_neighbors_mode, hit_neighbors_dam, x, y, 0);
00367 }
00368
00369 static void artillery_hit_neighbors(MAP * map, artillery_shot * s,
00370 int type, int mode, int dam, int tx,
00371 int ty)
00372 {
00373 hit_neighbors_s = s;
00374 hit_neighbors_type = type;
00375 hit_neighbors_mode = mode;
00376 hit_neighbors_dam = dam;
00377 visit_neighbor_hexes(map, tx, ty, artillery_hit_neighbors_callback);
00378 }
00379
00380 static void artillery_cluster_hit(MAP * map, artillery_shot * s, int type,
00381 int mode, int dam, int tx, int ty)
00382 {
00383
00384
00385 int xd, yd, x, y;
00386 int i;
00387
00388 int targets[5][5];
00389 int d;
00390
00391 bzero(targets, sizeof(targets));
00392 for(i = 0; i < dam; i++) {
00393 do {
00394 xd = Number(-2, 0) + Number(0, 2);
00395 yd = Number(-2, 0) + Number(0, 2);
00396 x = tx + xd;
00397 y = ty + yd;
00398 }
00399 while (x < 0 || x >= map->map_width || y < 0 || y >= map->map_height);
00400
00401 targets[xd + 2][yd + 2]++;
00402 }
00403 for(xd = 0; xd < 5; xd++)
00404 for(yd = 0; yd < 5; yd++)
00405 if((d = targets[xd][yd]))
00406 artillery_hit_hex(map, s, type, mode, d * 2, xd + tx - 2,
00407 yd + ty - 2, 1);
00408 }
00409
00410 void artillery_FriendlyAdjustment(dbref mechnum, MAP * map, int x, int y)
00411 {
00412 MECH *mech;
00413 MECH *spotter;
00414 MECH *tempMech = NULL;
00415
00416 if(!(mech = getMech(mechnum)))
00417 return;
00418
00419 spotter = getMech(MechSpotter(mech));
00420 if(!((MechTargX(mech) == x && MechTargY(mech) == y)
00421 || (spotter && (MechTargX(spotter) == x &&
00422 MechTargY(spotter) == y))))
00423 return;
00424
00425
00426 if(spotter) {
00427 if(MechSeesHex(spotter, map, x, y))
00428 tempMech = spotter;
00429 } else
00430 tempMech = find_mech_in_hex(mech, map, x, y, 2);
00431 if(!tempMech)
00432 return;
00433 if(!Started(tempMech) || !Started(mech))
00434 return;
00435 if(spotter) {
00436 mech_printf(mech, MECHSTARTED,
00437 "%s sent you some trajectory-correction data.",
00438 GetMechToMechID(mech, tempMech));
00439 mech_printf(tempMech, MECHSTARTED,
00440 "You provide %s with information about the miss.",
00441 GetMechToMechID(tempMech, mech));
00442 }
00443 MechFireAdjustment(mech)++;
00444 }
00445
00446 static void artillery_hit(artillery_shot * s)
00447 {
00448
00449
00450 double dir;
00451 int di;
00452 int dist;
00453 int weight;
00454 MAP *map = getMap(s->map);
00455 int original_x = 0, original_y = 0;
00456 int dam = MechWeapons[s->type].damage;
00457
00458 if(!map)
00459 return;
00460 if(!s->ishit) {
00461
00462
00463 di = Number(0, 359);
00464 dir = di * TWOPIOVER360;
00465 dist = Number(2, 7);
00466 weight = 100 * (dist * 6) / ((dist * 6 + map->windspeed));
00467 di = (di * weight + map->winddir * (100 - weight)) / 100;
00468 dist = (dist * weight + (map->windspeed / 6) * (100 - weight)) / 100;
00469 original_x = s->to_x;
00470 original_y = s->to_y;
00471 s->to_x = s->to_x + dist * cos(dir);
00472 s->to_y = s->to_y + dist * sin(dir);
00473 s->to_x = BOUNDED(0, s->to_x, map->map_width - 1);
00474 s->to_y = BOUNDED(0, s->to_y, map->map_height - 1);
00475
00476
00477
00478 }
00479
00480 if(!(s->mode & ARTILLERY_MODES))
00481 HexLOSBroadcast(map, s->to_x, s->to_y, tprintf("%s fire hits $H!",
00482 &MechWeapons[s->type].
00483 name[3]));
00484 else if(s->mode & CLUSTER_MODE)
00485 HexLOSBroadcast(map, s->to_x, s->to_y,
00486 "A rain of small bomblets hits $H's surroundings!");
00487 else if(s->mode & MINE_MODE)
00488 HexLOSBroadcast(map, s->to_x, s->to_y,
00489 "A rain of small bomblets hits $H!");
00490 else if(s->mode & SMOKE_MODE)
00491 HexLOSBroadcast(map, s->to_x, s->to_y,
00492 tprintf
00493 ("A %s %s hits $h, and smoke starts to billow!",
00494 &MechWeapons[s->type].name[3],
00495 &(artillery_type(s)[2])));
00496
00497
00498
00499
00500
00501
00502 if(!(s->mode & CLUSTER_MODE)) {
00503
00504 artillery_hit_hex(map, s, s->type, s->mode, dam, s->to_x, s->to_y, 1);
00505 if(!(s->mode & MINE_MODE))
00506 artillery_hit_neighbors(map, s, s->type, s->mode, dam / 2,
00507 s->to_x, s->to_y);
00508 } else
00509 artillery_cluster_hit(map, s, s->type, s->mode, dam, s->to_x,
00510 s->to_y);
00511 if(!s->ishit)
00512 artillery_FriendlyAdjustment(s->shooter, map, original_x, original_y);
00513 }