00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012 #include <stdio.h>
00013 #include <stdlib.h>
00014 #include <math.h>
00015 #include <sys/file.h>
00016
00017 #include "mech.h"
00018 #include "map.h"
00019 #include "mech.events.h"
00020 #include "mech.physical.h"
00021 #include "p.mech.physical.h"
00022 #include "p.mech.combat.h"
00023 #include "p.mech.damage.h"
00024 #include "p.mech.utils.h"
00025 #include "p.mech.los.h"
00026 #include "p.mech.hitloc.h"
00027 #include "p.bsuit.h"
00028 #include "p.btechstats.h"
00029 #include "p.template.h"
00030 #include "p.mech.bth.h"
00031
00032
00033 #define ARM_PHYS_CHECK(a) \
00034 DOCHECK(MechType(mech) == CLASS_MW || MechType(mech) == CLASS_BSUIT, \
00035 tprintf("You cannot %s without a 'mech!", a)); \
00036 DOCHECK(MechType(mech) != CLASS_MECH, \
00037 tprintf("You cannot %s with this vehicle!", a));
00038
00039
00040 #define GENERIC_CHECK(a,wDeadLegs) \
00041 ARM_PHYS_CHECK(a);\
00042 DOCHECK(!MechIsQuad(mech) && (wDeadLegs > 1), \
00043 "Without legs? Are you kidding?");\
00044 DOCHECK(!MechIsQuad(mech) && (wDeadLegs > 0),\
00045 "With one leg? Are you kidding?");\
00046 DOCHECK(wDeadLegs > 1,"It'd unbalance you too much in your condition..");\
00047 DOCHECK(wDeadLegs > 2, "Exactly _what_ are you going to kick with?");
00048
00049
00050 #define QUAD_CHECK(a) \
00051 DOCHECK(MechType(mech) == CLASS_MECH && MechIsQuad(mech), \
00052 tprintf("What are you going to %s with, your front right leg?", a))
00053
00057 int all_limbs_recycled(MECH * mech)
00058 {
00059 if(MechSections(mech)[LARM].recycle || MechSections(mech)[RARM].recycle) {
00060 mech_notify(mech, MECHALL,
00061 "You still have arms recovering from another attack.");
00062 return 0;
00063 }
00064
00065 if(MechSections(mech)[RLEG].recycle || MechSections(mech)[LLEG].recycle) {
00066 mech_notify(mech, MECHALL,
00067 "Your legs are still recovering from your last attack.");
00068 return 0;
00069 }
00070
00071 return 1;
00072 }
00073
00077 char *phys_form(int AttackType, int add_s)
00078 {
00079
00080 char *verb;
00081
00082
00083 if(add_s) {
00084
00085 switch (AttackType) {
00086 case PA_PUNCH:
00087 verb = "punchs";
00088 break;
00089 case PA_CLUB:
00090 verb = "clubs";
00091 break;
00092 case PA_MACE:
00093 verb = "maces";
00094 break;
00095 case PA_SWORD:
00096 verb = "chops";
00097 break;
00098 case PA_AXE:
00099 verb = "axes";
00100 break;
00101 case PA_KICK:
00102 verb = "kicks";
00103 break;
00104 case PA_TRIP:
00105 verb = "trips";
00106 break;
00107 case PA_SAW:
00108 verb = "saws";
00109 break;
00110
00111 default:
00112 verb = "??bugs??";
00113 }
00114 } else {
00115
00116 switch (AttackType) {
00117 case PA_PUNCH:
00118 verb = "punch";
00119 break;
00120 case PA_CLUB:
00121 verb = "club";
00122 break;
00123 case PA_MACE:
00124 verb = "maces";
00125 break;
00126 case PA_SWORD:
00127 verb = "chop";
00128 break;
00129 case PA_AXE:
00130 verb = "axe";
00131 break;
00132 case PA_KICK:
00133 verb = "kick";
00134 break;
00135 case PA_TRIP:
00136 verb = "trip";
00137 break;
00138 case PA_SAW:
00139 verb = "saw";
00140 break;
00141
00142 default:
00143 verb = "??bugs??";
00144 }
00145 }
00146
00147 return verb;
00148 }
00149
00150 #define phys_message(txt) \
00151 MechLOSBroadcasti(mech,target,txt)
00152
00153 void phys_succeed(MECH * mech, MECH * target, int at)
00154 {
00155 phys_message(tprintf("%s %%s!", phys_form(at, 1)));
00156 }
00157
00158 void phys_fail(MECH * mech, MECH * target, int at)
00159 {
00160 phys_message(tprintf("attempts to %s %%s!", phys_form(at, 0)));
00161 }
00162
00163
00164
00165
00166 static int have_punch(MECH * mech, int loc)
00167 {
00168 return 1;
00169 }
00170
00174 int have_axe(MECH * mech, int loc)
00175 {
00176 return FindObj(mech, loc, I2Special(AXE)) >= (MechTons(mech) / 15);
00177 }
00178
00182 int have_saw(MECH * mech, int loc)
00183 {
00184 return FindObj(mech, loc, I2Special(DUAL_SAW)) >= 7;
00185 }
00186
00190 int have_sword(MECH * mech, int loc)
00191 {
00192 return FindObj(mech, loc,
00193 I2Special(SWORD)) >= ((MechTons(mech) + 15) / 20);
00194 }
00195
00199 int have_mace(MECH * mech, int loc)
00200 {
00201 return FindObj(mech, loc, I2Special(MACE)) >= (MechTons(mech) / 10);
00202 }
00203
00204
00205
00206
00207 int phys_common_checks(MECH * mech)
00208 {
00209 if(Jumping(mech)) {
00210 mech_notify(mech, MECHALL,
00211 "You can't perform physical attacks while in the air!");
00212 return 0;
00213 }
00214
00215 if(Standing(mech)) {
00216 mech_notify(mech, MECHALL, "You are still trying to stand up!");
00217 return 0;
00218 }
00219 #ifdef BT_MOVEMENT_MODES
00220 if(Dodging(mech) || MoveModeLock(mech)) {
00221 mech_notify(mech, MECHALL,
00222 "You cannot use physicals while using a special movement mode.");
00223 return 0;
00224 }
00225 #endif
00226
00227 if(!all_limbs_recycled(mech)) {
00228 return 0;
00229 }
00230
00231 return 1;
00232 }
00233
00234
00235
00236
00237
00238 static int get_arm_args(int *using, int *argc, char ***args, MECH * mech,
00239 int (*have_fn) (MECH * mech, int loc), char *weapon)
00240 {
00241
00242 if(*argc != 0 && args[0][0][0] != '\0' && args[0][0][1] == '\0') {
00243 char arm = toupper(args[0][0][0]);
00244
00245
00246 switch (arm) {
00247 case 'B':
00248 *using = P_LEFT | P_RIGHT;
00249 --*argc;
00250 ++*args;
00251 break;
00252
00253 case 'L':
00254 *using = P_LEFT;
00255 --*argc;
00256 ++*args;
00257 break;
00258
00259 case 'R':
00260 *using = P_RIGHT;
00261 --*argc;
00262 ++*args;
00263 }
00264 }
00265
00266
00267
00268 switch (*using) {
00269 case P_LEFT:
00270 if(!have_fn(mech, LARM)) {
00271 mech_printf(mech, MECHALL,
00272 "You don't have %s in your left arm!", weapon);
00273 return 1;
00274 }
00275 break;
00276
00277 case P_RIGHT:
00278 if(!have_fn(mech, RARM)) {
00279 mech_printf(mech, MECHALL,
00280 "You don't have %s in your right arm!", weapon);
00281 return 1;
00282 }
00283 break;
00284
00285 case P_LEFT | P_RIGHT:
00286 if(!have_fn(mech, LARM))
00287 *using &= ~P_LEFT;
00288 if(!have_fn(mech, RARM))
00289 *using &= ~P_RIGHT;
00290 break;
00291 }
00292
00293
00294 return 0;
00295 }
00296
00300 int punch_checkArm(MECH * mech, int arm)
00301 {
00302 char *arm_used = (arm == LARM ? "left" : "right");
00303
00304 if(SectIsDestroyed(mech, arm)) {
00305 mech_printf(mech, MECHALL,
00306 "Your %s arm is destroyed, you can't punch with it.",
00307 arm_used);
00308 return 0;
00309 } else if(!OkayCritSectS(arm, 0, SHOULDER_OR_HIP)) {
00310 mech_printf(mech, MECHALL,
00311 "Your %s shoulder is destroyed, you can't punch with that arm.",
00312 arm_used);
00313 return 0;
00314 } else if(MechSections(mech)[arm].specials & CARRYING_CLUB) {
00315 mech_printf(mech, MECHALL,
00316 "You're carrying a club in your %s arm and can't punch with it.",
00317 arm_used);
00318 return 0;
00319 }
00320
00321 return 1;
00322 }
00323
00327 void mech_punch(dbref player, void *data, char *buffer)
00328 {
00329 MECH *mech = (MECH *) data;
00330 MAP *mech_map = getMap(mech->mapindex);
00331 char *argl[5];
00332 char **args = argl;
00333 int argc, ltohit = 4, rtohit = 4;
00334 int punching = P_LEFT | P_RIGHT;
00335
00336
00337 cch(MECH_USUALO);
00338
00339 ARM_PHYS_CHECK("punch");
00340
00341 QUAD_CHECK("punch");
00342
00343 argc = mech_parseattributes(buffer, args, 5);
00344
00345
00346
00347 if(mudconf.btech_phys_use_pskill)
00348 ltohit = rtohit = FindPilotPiloting(mech) - 1;
00349
00350
00351 if(get_arm_args(&punching, &argc, &args, mech, have_punch, "")) {
00352 return;
00353 }
00354
00355
00356
00357 if(!phys_common_checks(mech))
00358 return;
00359
00360
00361
00362 if(punching & P_LEFT) {
00363 if(punch_checkArm(mech, LARM))
00364 PhysicalAttack(mech, 10, ltohit, PA_PUNCH, argc, args,
00365 mech_map, LARM);
00366 }
00367
00368 if(punching & P_RIGHT) {
00369 if(punch_checkArm(mech, RARM))
00370 PhysicalAttack(mech, 10, rtohit, PA_PUNCH, argc, args,
00371 mech_map, RARM);
00372 }
00373 }
00374
00378 void mech_club(dbref player, void *data, char *buffer)
00379 {
00380 MECH *mech = (MECH *) data;
00381 MAP *mech_map = getMap(mech->mapindex);
00382 char *args[5];
00383 int argc;
00384 int clubLoc = -1;
00385
00386
00387 cch(MECH_USUALO);
00388
00389 ARM_PHYS_CHECK("club");
00390
00391 QUAD_CHECK("club");
00392
00393 if(MechSections(mech)[RARM].specials & CARRYING_CLUB)
00394 clubLoc = RARM;
00395 else if(MechSections(mech)[LARM].specials & CARRYING_CLUB)
00396 clubLoc = LARM;
00397
00398 if(clubLoc == -1) {
00399 DOCHECKMA(MechRTerrain(mech) != HEAVY_FOREST &&
00400 MechRTerrain(mech) != LIGHT_FOREST,
00401 "You can not seem to find any trees around to club with.");
00402
00403 clubLoc = RARM;
00404 }
00405
00406 argc = mech_parseattributes(buffer, args, 5);
00407
00408 DOCHECKMA(SectIsDestroyed(mech, LARM),
00409 "Your left arm is destroyed, you can't club.");
00410 DOCHECKMA(SectIsDestroyed(mech, RARM),
00411 "Your right arm is destroyed, you can't club.");
00412 DOCHECKMA(!OkayCritSectS(RARM, 0, SHOULDER_OR_HIP),
00413 "You can't club anyone with a destroyed or missing right shoulder.");
00414 DOCHECKMA(!OkayCritSectS(LARM, 0, SHOULDER_OR_HIP),
00415 "You can't club anyone with a destroyed or missing left shoulder.");
00416 DOCHECKMA(!OkayCritSectS(RARM, 3, HAND_OR_FOOT_ACTUATOR),
00417 "You can't club anyone with a destroyed or missing right hand.");
00418 DOCHECKMA(!OkayCritSectS(LARM, 3, HAND_OR_FOOT_ACTUATOR),
00419 "You can't club anyone with a destroyed or missing left hand.");
00420
00421
00422
00423
00424
00425 DOCHECKMA(SectHasBusyWeap(mech, LARM) || SectHasBusyWeap(mech, RARM),
00426 "You have weapons recycling on your arms.");
00427
00428 PhysicalAttack(mech, 5,
00429 (mudconf.btech_phys_use_pskill ? FindPilotPiloting(mech) - 1
00430 : 4), PA_CLUB, argc,
00431 args, mech_map, RARM);
00432 }
00433
00437 int axe_checkArm(MECH * mech, int arm)
00438 {
00439 char *arm_used = (arm == RARM ? "right" : "left");
00440
00441 if(SectIsDestroyed(mech, arm)) {
00442 mech_printf(mech, MECHALL,
00443 "Your %s arm is destroyed, you can't axe with it",
00444 arm_used);
00445 return 0;
00446 } else if(!OkayCritSectS(arm, 0, SHOULDER_OR_HIP)) {
00447 mech_printf(mech, MECHALL,
00448 "Your %s shoulder is destroyed, you can't axe with that arm.",
00449 arm_used);
00450 return 0;
00451 } else if(!OkayCritSectS(arm, 3, HAND_OR_FOOT_ACTUATOR)) {
00452 mech_printf(mech, MECHALL,
00453 "Your left hand is destroyed, you can't axe with that arm.",
00454 arm_used);
00455 return 0;
00456 }
00457
00458 return 1;
00459 }
00460
00464 void mech_axe(dbref player, void *data, char *buffer)
00465 {
00466 MECH *mech = (MECH *) data;
00467 MAP *mech_map = getMap(mech->mapindex);
00468 char *argl[5];
00469 char **args = argl;
00470 int argc, ltohit = 4, rtohit = 4;
00471 int using = P_LEFT | P_RIGHT;
00472
00473
00474 cch(MECH_USUALO);
00475
00476 ARM_PHYS_CHECK("axe");
00477
00478 QUAD_CHECK("axe");
00479
00480 argc = mech_parseattributes(buffer, args, 5);
00481
00482
00483
00484 if(mudconf.btech_phys_use_pskill)
00485 ltohit = rtohit = FindPilotPiloting(mech) - 1;
00486
00487
00488 if(get_arm_args(&using, &argc, &args, mech, have_axe, "an axe")) {
00489 return;
00490 }
00491
00492 if(using & P_LEFT) {
00493 if(axe_checkArm(mech, LARM))
00494 PhysicalAttack(mech, 5, ltohit, PA_AXE, argc, args, mech_map,
00495 LARM);
00496 }
00497 if(using & P_RIGHT) {
00498 if(axe_checkArm(mech, RARM))
00499 PhysicalAttack(mech, 5, rtohit, PA_AXE, argc, args, mech_map,
00500 RARM);
00501 }
00502
00503 DOCHECKMA(!using,
00504 "You may lack the axe, but not the will! Try punch/club until you find one.");
00505 }
00506
00510 int saw_checkArm(MECH * mech, int arm)
00511 {
00512 char *arm_used = (arm == RARM ? "right" : "left");
00513
00514 if(SectIsDestroyed(mech, arm)) {
00515 mech_printf(mech, MECHALL,
00516 "Your %s arm is destroyed, you can't saw with it",
00517 arm_used);
00518 return 0;
00519 } else if(!OkayCritSectS(arm, 0, SHOULDER_OR_HIP)) {
00520 mech_printf(mech, MECHALL,
00521 "Your %s shoulder is destroyed, you can't saw with that arm.",
00522 arm_used);
00523 return 0;
00524 }
00525
00526 return 1;
00527 }
00528
00532 void mech_saw(dbref player, void *data, char *buffer)
00533 {
00534 MECH *mech = (MECH *) data;
00535 MAP *mech_map = getMap(mech->mapindex);
00536 char *argl[5];
00537 char **args = argl;
00538 int argc, ltohit = 4, rtohit = 4;
00539 int using = P_LEFT | P_RIGHT;
00540
00541
00542 cch(MECH_USUALO);
00543
00544 ARM_PHYS_CHECK("saw");
00545
00546 QUAD_CHECK("saw");
00547
00548 argc = mech_parseattributes(buffer, args, 5);
00549
00550
00551
00552 if(mudconf.btech_phys_use_pskill)
00553 ltohit = rtohit = FindPilotPiloting(mech) - 1;
00554
00555
00556 if(get_arm_args(&using, &argc, &args, mech, have_saw, "a saw")) {
00557 return;
00558 }
00559
00560 if(using & P_LEFT) {
00561 if(saw_checkArm(mech, LARM))
00562 PhysicalAttack(mech, 7, ltohit, PA_SAW, argc, args, mech_map,
00563 LARM);
00564 }
00565 if(using & P_RIGHT) {
00566 if(saw_checkArm(mech, RARM))
00567 PhysicalAttack(mech, 7, rtohit, PA_SAW, argc, args, mech_map,
00568 RARM);
00569 }
00570
00571 DOCHECKMA(!using, "You don't have a dual saw!");
00572 }
00573
00577 int mace_checkArm(MECH * mech, int arm)
00578 {
00579 char *arm_used = (arm == RARM ? "right" : "left");
00580
00581 if(SectIsDestroyed(mech, arm)) {
00582 mech_printf(mech, MECHALL,
00583 "Your %s arm is destroyed, you can't use a mace with it.",
00584 arm_used);
00585 return 0;
00586 } else if(!OkayCritSectS(arm, 0, SHOULDER_OR_HIP)) {
00587 mech_printf(mech, MECHALL,
00588 "Your %s shoulder is destroyed, you can't use a mace with that arm.",
00589 arm_used);
00590 return 0;
00591 } else if(!OkayCritSectS(arm, 3, HAND_OR_FOOT_ACTUATOR)) {
00592 mech_printf(mech, MECHALL,
00593 "Your %s hand is destroyed, you can't use a mace with that arm.",
00594 arm_used);
00595 return 0;
00596 }
00597
00598 return 1;
00599 }
00600
00604 void mech_mace(dbref player, void *data, char *buffer)
00605 {
00606 MECH *mech = (MECH *) data;
00607 MAP *mech_map = getMap(mech->mapindex);
00608 char *argl[5];
00609 char **args = argl;
00610 int argc, ltohit = 4, rtohit = 4;
00611 int using = P_LEFT | P_RIGHT;
00612
00613
00614 cch(MECH_USUALO);
00615
00616 ARM_PHYS_CHECK("mace");
00617
00618 QUAD_CHECK("mace");
00619
00620 argc = mech_parseattributes(buffer, args, 5);
00621
00622
00623
00624 if(mudconf.btech_phys_use_pskill)
00625 ltohit = rtohit = FindPilotPiloting(mech) - 1;
00626
00627
00628 if(get_arm_args(&using, &argc, &args, mech, have_mace, "a mace")) {
00629 return;
00630 }
00631
00632 if(using & P_LEFT) {
00633 if(mace_checkArm(mech, LARM))
00634 PhysicalAttack(mech, 4, ltohit, PA_MACE, argc, args, mech_map,
00635 LARM);
00636 }
00637 if(using & P_RIGHT) {
00638 if(mace_checkArm(mech, RARM))
00639 PhysicalAttack(mech, 4, rtohit, PA_MACE, argc, args, mech_map,
00640 RARM);
00641 }
00642
00643 DOCHECKMA(!using, "You don't have a mace!");
00644 }
00645
00649 int sword_checkArm(MECH * mech, int arm)
00650 {
00651 char *arm_used = (arm == RARM ? "right" : "left");
00652
00653 if(SectIsDestroyed(mech, arm)) {
00654 mech_printf(mech, MECHALL,
00655 "Your %s arm is destroyed, you can't use a sword with it.",
00656 arm_used);
00657 return 0;
00658 } else if(!OkayCritSectS(arm, 0, SHOULDER_OR_HIP)) {
00659 mech_printf(mech, MECHALL,
00660 "Your %s shoulder is destroyed, you can't use a sword with that arm.",
00661 arm_used);
00662 return 0;
00663 } else if(!OkayCritSectS(arm, 3, HAND_OR_FOOT_ACTUATOR)) {
00664 mech_printf(mech, MECHALL,
00665 "Your %s hand is destroyed, you can't use a sword with that arm.",
00666 arm_used);
00667 return 0;
00668 }
00669
00670 return 1;
00671 }
00672
00676 void mech_sword(dbref player, void *data, char *buffer)
00677 {
00678 MECH *mech = (MECH *) data;
00679 MAP *mech_map = getMap(mech->mapindex);
00680 char *argl[5];
00681 char **args = argl;
00682 int argc, ltohit = 3, rtohit = 3;
00683 int using = P_LEFT | P_RIGHT;
00684
00685
00686 cch(MECH_USUALO);
00687
00688 ARM_PHYS_CHECK("chop");
00689
00690 QUAD_CHECK("chop");
00691
00692 argc = mech_parseattributes(buffer, args, 5);
00693
00694
00695
00696 if(mudconf.btech_phys_use_pskill)
00697 ltohit = rtohit = FindPilotPiloting(mech) - 2;
00698
00699
00700 if(get_arm_args(&using, &argc, &args, mech, have_sword, "a sword")) {
00701 return;
00702 }
00703
00704 if(using & P_LEFT) {
00705 if(sword_checkArm(mech, LARM))
00706 PhysicalAttack(mech, 10, ltohit, PA_SWORD, argc, args, mech_map,
00707 LARM);
00708 }
00709
00710 if(using & P_RIGHT) {
00711 if(sword_checkArm(mech, RARM))
00712 PhysicalAttack(mech, 10, rtohit, PA_SWORD, argc, args, mech_map,
00713 RARM);
00714 }
00715
00716 DOCHECKMA(!using, "You have no sword to chop people with!");
00717 }
00718
00722 void mech_trip(dbref player, void *data, char *buffer)
00723 {
00724 mech_kickortrip(player, data, buffer, PA_TRIP);
00725 }
00726
00730 void mech_kick(dbref player, void *data, char *buffer)
00731 {
00732 mech_kickortrip(player, data, buffer, PA_KICK);
00733 }
00734
00738 void mech_kickortrip(dbref player, void *data, char *buffer, int AttackType)
00739 {
00740 MECH *mech = (MECH *) data;
00741 MAP *mech_map = getMap(mech->mapindex);
00742 char *argl[5];
00743 char **args = argl;
00744 int argc;
00745 int rl = RLEG, ll = LLEG;
00746 int leg;
00747 int using = P_RIGHT;
00748
00749
00750 cch(MECH_USUALO);
00751
00752 if(MechIsQuad(mech)) {
00753 rl = RARM;
00754 ll = LARM;
00755 }
00756
00757 GENERIC_CHECK("kick", CountDestroyedLegs(mech));
00758
00759 argc = mech_parseattributes(buffer, args, 5);
00760
00761
00762 if(get_arm_args(&using, &argc, &args, mech, have_punch, "")) {
00763 return;
00764 }
00765
00766 switch (using) {
00767 case P_LEFT:
00768 leg = ll;
00769 break;
00770
00771 case P_RIGHT:
00772 leg = rl;
00773 break;
00774
00775 default:
00776 case P_LEFT | P_RIGHT:
00777 mech_notify(mech, MECHALL,
00778 "What, yer gonna LEVITATE? I Don't Think So.");
00779 return;
00780 }
00781
00782 if((MechCritStatus(mech) & HIP_DAMAGED))
00783 {
00784 mech_printf(mech, MECHALL,
00785 "You can't %s with a destroyed hip.",
00786 phys_form(AttackType, 0));
00787 return;
00788 }
00789
00790 PhysicalAttack(mech, 5,
00791 (mudconf.btech_phys_use_pskill ? FindPilotPiloting(mech) -
00792 2 : 3), AttackType, argc, args, mech_map, leg);
00793 }
00794
00798 void mech_charge(dbref player, void *data, char *buffer)
00799 {
00800 MECH *mech = (MECH *) data, *target;
00801 MAP *mech_map = getMap(mech->mapindex);
00802 int targetnum;
00803 char targetID[5];
00804 char *args[5];
00805 int argc;
00806 int wcDeadLegs = 0;
00807
00808
00809 cch(MECH_USUALO);
00810
00811
00812 DOCHECK(MechType(mech) == CLASS_MW ||
00813 MechType(mech) == CLASS_BSUIT,
00814 "You cannot charge without a 'mech!");
00815
00816
00817 DOCHECK(MechType(mech) != CLASS_MECH &&
00818 (MechType(mech) != CLASS_VEH_GROUND ||
00819 MechSpecials(mech) & SALVAGE_TECH),
00820 "You cannot charge with this vehicle!");
00821
00822
00823 if(MechType(mech) == CLASS_MECH) {
00824
00825 wcDeadLegs = CountDestroyedLegs(mech);
00826
00827 DOCHECK(!MechIsQuad(mech) && (wcDeadLegs > 0),
00828 "With one leg? Are you kidding?");
00829 DOCHECK(!MechIsQuad(mech) && (wcDeadLegs > 1),
00830 "Without legs? Are you kidding?");
00831 DOCHECK(wcDeadLegs > 1,
00832 "It'd unbalance you too much in your condition..");
00833 DOCHECK(wcDeadLegs > 2, "Exactly _what_ are you going to kick with?");
00834 }
00835
00836 argc = mech_parseattributes(buffer, args, 2);
00837
00838 switch (argc) {
00839
00840 case 0:
00841 DOCHECKMA(MechTarget(mech) == -1,
00842 "You do not have a default target set!");
00843
00844 target = getMech(MechTarget(mech));
00845
00846 if(!target) {
00847 mech_notify(mech, MECHALL, "Invalid default target!");
00848 MechTarget(mech) = -1;
00849 return;
00850 }
00851
00852 if(MechType(target) == CLASS_MW) {
00853 mech_notify(mech, MECHALL,
00854 "You can't charge THAT sack of bones and squishy bits!");
00855 return;
00856 }
00857
00858 if(MapNoFriendlyFire(mech_map) && (MechTeam(mech) == MechTeam(target))) {
00859 mech_notify(mech, MECHALL, "You can't charge your own team!");
00860 MechChargeTarget(mech) = -1;
00861 return;
00862 }
00863
00864 MechChargeTarget(mech) = MechTarget(mech);
00865 mech_notify(mech, MECHALL, "Charge target set to default target.");
00866 break;
00867
00868
00869 case 1:
00870 if(args[0][0] == '-') {
00871 MechChargeTarget(mech) = -1;
00872 MechChargeTimer(mech) = 0;
00873 MechChargeDistance(mech) = 0;
00874 mech_notify(mech, MECHPILOT, "You are no longer charging.");
00875 return;
00876 }
00877
00878 targetID[0] = args[0][0];
00879 targetID[1] = args[0][1];
00880 targetnum = FindTargetDBREFFromMapNumber(mech, targetID);
00881
00882 DOCHECKMA(targetnum == -1, "Target is not in line of sight!");
00883
00884 target = getMech(targetnum);
00885 DOCHECKMA(!InLineOfSight_NB(mech, target, MechX(target),
00886 MechY(target), FaMechRange(mech, target)),
00887 "Target is not in line of sight!");
00888
00889 if(!target) {
00890 mech_notify(mech, MECHALL, "Invalid target data!");
00891 return;
00892 }
00893
00894 if(MapNoFriendlyFire(mech_map) && (MechTeam(mech) == MechTeam(target))) {
00895 mech_notify(mech, MECHALL, "You can't charge your own team!");
00896 MechChargeTarget(mech) = -1;
00897 return;
00898 }
00899
00900
00901 if(MechType(target) == CLASS_MW) {
00902 mech_notify(mech, MECHALL,
00903 "You can't charge THAT sack of bones and squishy bits!");
00904 return;
00905 }
00906
00907 MechChargeTarget(mech) = targetnum;
00908
00909 mech_printf(mech, MECHALL, "%s target set to %s.",
00910 MechType(mech) == CLASS_MECH ? "Charge" : "Ram",
00911 GetMechToMechID(mech, target));
00912 break;
00913
00914
00915 default:
00916 notify(player, "Invalid number of arguments!");
00917 }
00918 }
00919
00920
00921
00922
00923
00924
00925
00926
00927 void PhysicalAttack(MECH * mech, int damageweight, int baseToHit,
00928 int AttackType, int argc, char **args, MAP * mech_map,
00929 int sect)
00930 {
00931 MECH *target;
00932 float range;
00933 float maxRange = 1;
00934 char targetID[2];
00935 int targetnum, roll, swarmingUs;
00936 char location[20];
00937 int ts = 0, iwa;
00938 int RbaseToHit, glance = 0;
00939
00940
00941
00942
00943
00944
00945
00946
00947
00948 if(AttackType != PA_PUNCH)
00949 if(!phys_common_checks(mech))
00950 return;
00951
00952
00953
00954 if ((AttackType == PA_PUNCH) || (AttackType == PA_KICK) ||
00955 (AttackType == PA_AXE) || (AttackType == PA_SWORD) ||
00956 (AttackType == PA_MACE) || (AttackType == PA_SAW)) {
00957
00958 if (PartIsNonfunctional(mech, sect, 1) ||
00959 GetPartType(mech, sect, 1) != I2Special(UPPER_ACTUATOR)) {
00960 baseToHit += 2;
00961 }
00962
00963 if (PartIsNonfunctional(mech, sect, 2) ||
00964 GetPartType(mech, sect, 2) != I2Special(LOWER_ACTUATOR)) {
00965 baseToHit += 2;
00966 }
00967
00968
00969
00970 if ((AttackType == PA_PUNCH) || (AttackType == PA_KICK)) {
00971 if (PartIsNonfunctional(mech, sect, 3) ||
00972 GetPartType(mech, sect, 3) != I2Special(HAND_OR_FOOT_ACTUATOR)) {
00973 baseToHit += 1;
00974 }
00975 }
00976
00977 } else if (AttackType == PA_CLUB) {
00978
00979
00980
00981 if (PartIsNonfunctional(mech, RARM, 1) ||
00982 GetPartType(mech, sect, 1) != I2Special(UPPER_ACTUATOR)) {
00983 baseToHit += 2;
00984 }
00985 if (PartIsNonfunctional(mech, RARM, 2) ||
00986 GetPartType(mech, sect, 2) != I2Special(LOWER_ACTUATOR)) {
00987 baseToHit += 2;
00988 }
00989 if (PartIsNonfunctional(mech, LARM, 1) ||
00990 GetPartType(mech, sect, 1) != I2Special(UPPER_ACTUATOR)) {
00991 baseToHit += 2;
00992 }
00993 if (PartIsNonfunctional(mech, LARM, 2) ||
00994 GetPartType(mech, sect, 2) != I2Special(LOWER_ACTUATOR)) {
00995 baseToHit += 2;
00996 }
00997 }
00998
00999
01000 if(SectHasBusyWeap(mech, sect)) {
01001 ArmorStringFromIndex(sect, location, MechType(mech), MechMove(mech));
01002 mech_printf(mech, MECHALL,
01003 "You have weapons recycling on your %s.", location);
01004 return;
01005 }
01006
01007
01008 switch (argc) {
01009 case -1:
01010 case 0:
01011
01012 DOCHECKMA(MechTarget(mech) == -1, "You do not have a target set!");
01013
01014
01015 target = getMech(MechTarget(mech));
01016 DOCHECKMA(!target, "Invalid default target!");
01017
01018 break;
01019 default:
01020
01021
01022
01023
01024 targetID[0] = args[0][0];
01025 targetID[1] = args[0][1];
01026 targetnum = FindTargetDBREFFromMapNumber(mech, targetID);
01027 target = getMech(targetnum);
01028
01029 DOCHECKMA(targetnum == -1, "Target is not in line of sight!");
01030 DOCHECKMA(!target, "Invalid default target!");
01031 }
01032
01033
01034 swarmingUs = (MechSwarmTarget(target) == mech->mynum ? 1 : 0);
01035
01036
01037
01038
01039
01040
01041
01042 if(Fallen(mech) && (AttackType == PA_KICK || AttackType == PA_TRIP)) {
01043 mech_printf(mech, MECHALL, "You can't %s from a prone position.",
01044 phys_form(AttackType, 0));
01045
01046 return;
01047
01048
01049 } else if(Fallen(mech) &&
01050 (MechType(target) != CLASS_VEH_GROUND &&
01051 MechType(target) != CLASS_BSUIT)) {
01052 mech_printf(mech, MECHALL,
01053 "You can't %s from a prone position.",
01054 phys_form(AttackType, 0));
01055
01056 return;
01057 } else if(Fallen(mech) && MechType(target) == CLASS_BSUIT && !swarmingUs) {
01058 mech_notify(mech, MECHALL,
01059 "You may only physical suits that are swarming you while prone.");
01060 return;
01061 } else if(Fallen(mech) && MechType(target) == CLASS_VEH_GROUND &&
01062 AttackType != PA_PUNCH) {
01063 mech_notify(mech, MECHALL,
01064 "You may only punch vehicles while prone.");
01065 return;
01066 }
01067
01068 range = FaMechRange(mech, target);
01069
01070 DOCHECKMA(!InLineOfSight_NB(mech, target, MechX(target),
01071 MechY(target), range),
01072 "Target is not in line of sight!");
01073
01074
01075 if((MechType(target) == CLASS_BSUIT) || (MechType(target) == CLASS_MW))
01076 maxRange = 0.5;
01077
01078 DOCHECKMA(range >= maxRange, "Target out of range!");
01079
01080 DOCHECKMA(Jumping(target),
01081 "You can't perform physical attacks on airborne mechs!");
01082
01083 DOCHECKMA(MechTeam(target) == MechTeam(mech) &&
01084 MechNoFriendlyFire(mech),
01085 "You can't attack a teammate with FFSafeties on!");
01086
01087 DOCHECKMA(MechTeam(target) == MechTeam(mech) &&
01088 MapNoFriendlyFire(mech_map),
01089 "Friendly Fire? I don't think so...");
01090
01091 DOCHECKMA(MechType(target) == CLASS_MW && !MechPKiller(mech),
01092 "That's a living, breathing person! Switch off the safety first, "
01093 "if you really want to assassinate the target.");
01094
01095 DOCHECKMA(MechCritStatus(mech) & MECH_STUNNED,
01096 "You are still recovering from your stunning experience!");
01097
01098
01099
01100 DOCHECKMA(AttackType == PA_PUNCH &&
01101 (MechType(target) == CLASS_VEH_GROUND) &&
01102 !Fallen(mech),
01103 "You can't punch vehicles unless you are prone!");
01104
01105
01106 DOCHECKMA(AttackType == PA_TRIP && MechType(target) != CLASS_MECH,
01107 "You can only trip mechs!");
01108
01109
01110 DOCHECKMA(AttackType == PA_TRIP && (Fallen(target) || Standing(target)),
01111 "Your target is already down!");
01112
01113
01114 if(MechMove(target) != MOVE_VTOL && MechMove(target) != MOVE_FLY) {
01115
01116 if((AttackType != PA_KICK && AttackType != PA_TRIP) &&
01117 (MechZ(mech) >= MechZ(target))) {
01118 int isTooLow = 0;
01119
01120
01121 if(MechType(target) == CLASS_MECH && Fallen(target))
01122 isTooLow = 1;
01123
01124
01125 if ((MechType(target) == CLASS_MECH) &&
01126 (MechZ(mech) > MechZ(target)) &&
01127 (AttackType == PA_PUNCH)) {
01128 isTooLow = 1;
01129 }
01130
01131
01132 if(MechType(target) != CLASS_MECH &&
01133 MechType(target) != CLASS_BSUIT && !IsDS(target))
01134 isTooLow = 1;
01135
01136
01137
01138 if(AttackType == PA_PUNCH &&
01139 MechType(target) == CLASS_VEH_GROUND && Fallen(mech))
01140 isTooLow = 0;
01141
01142
01143 if(MechType(target) == CLASS_BSUIT && MechSwarmTarget(target) > 0) {
01144 mech_printf(mech, MECHALL,
01145 "You can't directly physical suits that are swarmed or mounted on another mech!");
01146 return;
01147 }
01148
01149 if(isTooLow == 1) {
01150 mech_printf(mech, MECHALL,
01151 "The target is too low in elevation for you to %s.",
01152 phys_form(AttackType, 0));
01153 return;
01154 }
01155 }
01156
01157 DOCHECKMA((AttackType == PA_KICK || AttackType == PA_TRIP) &&
01158 MechZ(mech) < MechZ(target),
01159 "The target is too high in elevation for you to kick at.");
01160
01161 DOCHECKMA(MechZ(mech) - MechZ(target) > 1 ||
01162 MechZ(target) - MechZ(mech) > 1,
01163 "You can't attack, the elevation difference is too large.");
01164
01165 DOCHECKMA((AttackType == PA_KICK || AttackType == PA_TRIP) &&
01166 (MechZ(target) < MechZ(mech) &&
01167 (((MechType(target) == CLASS_MECH) && Fallen(target)) ||
01168 (MechType(target) == CLASS_VEH_GROUND) ||
01169 (MechType(target) == CLASS_BSUIT) ||
01170 (MechType(target) == CLASS_MW))),
01171 "The target is too low in elevation for you to kick.")
01172
01173 } else {
01174
01175 if((AttackType != PA_KICK) && MechZ(target) - MechZ(mech) > 3) {
01176 mech_printf(mech, MECHALL,
01177 "The target is too far away for you to %s.",
01178 phys_form(AttackType, 0));
01179 }
01180
01181 if((AttackType == PA_KICK || AttackType == PA_TRIP) &&
01182 MechZ(mech) != MechZ(target)) {
01183 mech_printf(mech, MECHALL,
01184 "The target is too far away for you to %s.",
01185 phys_form(AttackType, 0));
01186 return;
01187 }
01188
01189 DOCHECKMA(!(MechZ(target) - MechZ(mech) > -1 &&
01190 MechZ(target) - MechZ(mech) < 4),
01191 "You can't attack, the elevation difference is too large.");
01192 }
01193
01194
01195
01196
01197
01198
01199
01200
01201
01202
01203
01204 if(AttackType == PA_KICK || AttackType == PA_TRIP) {
01205
01206 ts = MechStatus(mech) & (TORSO_LEFT | TORSO_RIGHT);
01207 MechStatus(mech) &= ~ts;
01208 iwa = InWeaponArc(mech, MechFX(target), MechFY(target));
01209 MechStatus(mech) |= ts;
01210
01211 DOCHECKMA(!(iwa & FORWARDARC),
01212 "Target is not in your 'real' forward arc!");
01213
01214 } else {
01215
01216 iwa = InWeaponArc(mech, MechFX(target), MechFY(target));
01217
01218 if(AttackType == PA_CLUB) {
01219
01220
01221 DOCHECKMA(!(iwa & FORWARDARC) && swarmingUs != 1,
01222 "Target is not in your forward arc!");
01223 } else {
01224
01225 if(sect == RARM) {
01226
01227 DOCHECKMA(!
01228 ((iwa & FORWARDARC) || (iwa & RSIDEARC)
01229 || swarmingUs),
01230 "Target is not in your forward or right side arc!");
01231 } else {
01232
01233 DOCHECKMA(!((iwa & FORWARDARC) || (iwa & LSIDEARC))
01234 || swarmingUs,
01235 "Target is not in your forward or left side arc!");
01236
01237 }
01238
01239 }
01240
01241 }
01242
01247
01248 baseToHit += HasBoolAdvantage(MechPilot(mech), "melee_specialist") ?
01249 MIN(0, AttackMovementMods(mech) - 1) : AttackMovementMods(mech);
01250
01251 baseToHit += TargetMovementMods(mech, target, 0.0);
01252
01253
01254 baseToHit += MechType(target) == CLASS_BSUIT ? 1 : 0;
01255
01256
01257 baseToHit += ((MechType(target) == CLASS_BSUIT) &&
01258 (AttackType == PA_KICK)) ? 3 : 0;
01259
01260 #ifdef MOVEMENT_MODES
01261
01262 if(Dodging(target))
01263 baseToHit += 2;
01264 #endif
01265
01266
01267 if(AttackType == PA_SAW)
01268 baseToHit += 1;
01269
01270
01271 if(AttackType == PA_MACE)
01272 baseToHit += 2;
01273
01274
01275 if(AttackType != PA_PUNCH &&
01276 MechType(target) == CLASS_BSUIT && MechSwarmTarget(target) > 0)
01277 baseToHit += (AttackType != PA_PUNCH) ? 3 : 5;
01278
01279
01280
01281 DOCHECKMA(AttackType == PA_KICK &&
01282 MechType(target) == CLASS_BSUIT &&
01283 MechSwarmTarget(target) > 0,
01284 "You can't hit a swarmed suit with that, try a hand-held weapon!");
01285
01286
01287
01288
01289
01290
01291 if (MechTerrain(target) == SMOKE) {
01292 baseToHit += 2;
01293 } else if (MechRTerrain(target) == HEAVY_FOREST) {
01294 baseToHit += 2;
01295 } else if (MechRTerrain(target) == LIGHT_FOREST) {
01296 baseToHit += 1;
01297 }
01298
01299 roll = Roll();
01300
01301
01302 mech_printf(mech, MECHALL,
01303 "You try to %s %s. BTH: %d,\tRoll: %d",
01304 phys_form(AttackType, 0),
01305 GetMechToMechID(mech, target), baseToHit, roll);
01306
01307 mech_printf(target, MECHSTARTED, "%s tries to %s you!",
01308 GetMechToMechID(target, mech), phys_form(AttackType, 0));
01309
01310
01311 SendAttacks(tprintf("#%i attacks #%i (%s) (%i/%i)",
01312 mech->mynum,
01313 target->mynum,
01314 phys_form(AttackType, 0), baseToHit, roll));
01315
01316
01317 SetRecycleLimb(mech, sect, PHYSICAL_RECYCLE_TIME);
01318
01319
01320
01321
01322 if(AttackType == PA_AXE || AttackType == PA_SWORD || AttackType == PA_SAW
01323 || AttackType == PA_MACE)
01324 MechSections(mech)[sect].config |= AXED;
01325
01326 if(AttackType == PA_PUNCH)
01327 MechSections(mech)[sect].config &= ~AXED;
01328
01329
01330 if(AttackType == PA_CLUB)
01331 SetRecycleLimb(mech, LARM, PHYSICAL_RECYCLE_TIME);
01332
01333 RbaseToHit = baseToHit;
01334 if(mudconf.btech_glancing_blows == 2)
01335 RbaseToHit = baseToHit - 1;
01336
01337 if(roll >= RbaseToHit) {
01338 phys_succeed(mech, target, AttackType);
01339 if (mudconf.btech_glancing_blows && (roll == RbaseToHit)) {
01340 MechLOSBroadcast(target,"is nicked by a glancing blow!");
01341 mech_notify(target, MECHALL, "You are nicked by a glancing blow!");
01342 glance = 1 ;
01343 }
01344 if(AttackType == PA_CLUB) {
01345 int clubLoc = -1;
01346
01347 if(MechSections(mech)[RARM].specials & CARRYING_CLUB)
01348 clubLoc = RARM;
01349 else if(MechSections(mech)[LARM].specials & CARRYING_CLUB)
01350 clubLoc = LARM;
01351
01352 if(clubLoc > -1) {
01353 mech_notify(mech, MECHALL, "Your club shatters on contact.");
01354 MechLOSBroadcast(mech,
01355 "'s club shatters with a loud *CRACK*!");
01356
01357 MechSections(mech)[clubLoc].specials &= ~CARRYING_CLUB;
01358 }
01359 }
01360
01361
01362
01363 if(AttackType != PA_TRIP)
01364 PhysicalDamage(mech, target, damageweight, AttackType, sect, glance);
01365 else
01366 PhysicalTrip(mech, target);
01367
01368 } else {
01369 phys_fail(mech, target, AttackType);
01370
01371 if(MechType(target) == CLASS_BSUIT &&
01372 MechSwarmTarget(target) == mech->mynum) {
01373
01374 if(!MadePilotSkillRoll(mech, 4)) {
01375 mech_notify(mech, MECHALL,
01376 "Uh oh. You miss the little buggers, but hit yourself!");
01377 MechLOSBroadcast(mech, "misses, and hits itself!");
01378
01379 PhysicalDamage(mech, mech, damageweight, AttackType, sect, glance);
01380 }
01381
01382 }
01383
01384
01385 if(AttackType == PA_KICK ||
01386 AttackType == PA_MACE) {
01387 int failRoll = (AttackType == PA_KICK ? 0 : 2);
01388
01389 mech_notify(mech, MECHALL,
01390 "You miss and try to remain standing!");
01391
01392
01393 if(!MadePilotSkillRoll(mech, failRoll)) {
01394 mech_notify(mech, MECHALL,
01395 "You lose your balance and fall down!");
01396 MechFalls(mech, 1, 1);
01397 }
01398 }
01399 }
01400 }
01401
01402 extern int global_physical_flag;
01403
01404 #define MyDamageMech(a,b,c,d,e,f,g,h,i) \
01405 global_physical_flag = 1 ; DamageMech(a,b,c,d,e,f,g,h,i,-1,0,-1,0,0); \
01406 global_physical_flag = 0
01407 #define MyDamageMech2(a,b,c,d,e,f,g,h,i) \
01408 global_physical_flag = 2 ; DamageMech(a,b,c,d,e,f,g,h,i,-1,0,-1,0,0); \
01409 global_physical_flag = 0
01410
01411
01412
01413
01414 void PhysicalTrip(MECH * mech, MECH * target)
01415 {
01416
01417 if(!MadePilotSkillRoll(target, 0) && !Fallen(target)) {
01418
01419
01420 mech_printf(mech, MECHALL,
01421 "You trip %s!", GetMechToMechID(mech, target));
01422
01423
01424 mech_notify(target, MECHSTARTED,
01425 "You are tripped and fall to the ground!");
01426 MechLOSBroadcast(target, "trips up and falls down!");
01427
01428 MechFalls(target, 1, 0);
01429 } else {
01430 MechLOSBroadcast(target, "manages to stay upright!");
01431 }
01432 }
01433
01434
01435
01436
01437 void PhysicalDamage(MECH * mech, MECH * target, int weightdmg,
01438 int AttackType, int sect, int glance) {
01439
01440 int hitloc = 0, damage, hitgroup = 0, isrear, iscritical, i;
01441
01442 isrear = 0;
01443 iscritical = 0;
01444
01445
01446
01447
01448 if (AttackType == PA_SAW) {
01449
01450
01451 damage = 7;
01452
01453 } else {
01454
01455
01456 if (AttackType == PA_SWORD) {
01457 damage = (MechTons(mech) + 5) / weightdmg + 1;
01458 } else {
01459 damage = (MechTons(mech) + weightdmg / 2) / weightdmg;
01460 }
01461
01462
01463 if ((MechHeat(mech) >= 9.) && (MechSpecials(mech) & TRIPLE_MYOMER_TECH)) {
01464 damage = damage * 2;
01465 }
01466
01467 }
01468
01469
01470 if (HasBoolAdvantage(MechPilot(mech), "melee_specialist")) {
01471 damage++;
01472 }
01473
01474 switch (AttackType) {
01475 case PA_PUNCH:
01476
01477 if (!OkayCritSectS(sect, 2, LOWER_ACTUATOR)) {
01478 damage = damage / 2;
01479 }
01480
01481 if (!OkayCritSectS(sect, 1, UPPER_ACTUATOR)) {
01482 damage = damage / 2;
01483 }
01484
01485 hitgroup = FindAreaHitGroup(mech, target);
01486 if (hitgroup == BACK) {
01487 isrear = 1;
01488 }
01489
01490 if (MechType(mech) == CLASS_MECH) {
01491
01492 if (Fallen(mech)) {
01493
01494
01495
01496
01497
01498 if ((MechType(target) != CLASS_MECH) || (Fallen(target) &&
01499 (MechElevation(mech) == MechElevation (target)))) {
01500 hitloc = FindTargetHitLoc(mech, target, &isrear, &iscritical);
01501 } else if (!Fallen(target) &&
01502 (MechElevation(mech) > MechElevation(target))) {
01503 hitloc = FindPunchLocation(target, hitgroup);
01504 } else if (MechElevation(mech) == MechElevation(target)) {
01505 hitloc = FindKickLocation(target, hitgroup);
01506 }
01507
01508 } else if (MechElevation(mech) < MechElevation(target)) {
01509
01510 if (Fallen(target) || MechType(target) != CLASS_MECH) {
01511 hitloc = FindTargetHitLoc(mech, target, &isrear, &iscritical);
01512 } else {
01513 hitloc = FindKickLocation(target, hitgroup);
01514 }
01515
01516 } else {
01517 hitloc = FindPunchLocation(target, hitgroup);
01518 }
01519
01520 } else {
01521 hitloc = FindTargetHitLoc(mech, target, &isrear, &iscritical);
01522 }
01523
01524 break;
01525
01526 case PA_SWORD:
01527 case PA_AXE:
01528 case PA_MACE:
01529 case PA_CLUB:
01530
01531 hitgroup = FindAreaHitGroup(mech, target);
01532 if (hitgroup == BACK) {
01533 isrear = 1;
01534 }
01535
01536 if (MechType(mech) == CLASS_MECH) {
01537
01538 if (MechElevation(mech) < MechElevation(target)) {
01539
01540 if (Fallen(target) || MechType(target) != CLASS_MECH) {
01541 hitloc = FindTargetHitLoc(mech, target, &isrear, &iscritical);
01542 } else {
01543 hitloc = FindKickLocation(target, hitgroup);
01544 }
01545
01546 } else if (MechElevation(mech) > MechElevation(target)) {
01547 hitloc = FindPunchLocation(target, hitgroup);
01548 } else {
01549 hitloc = FindTargetHitLoc(mech, target, &isrear, &iscritical);
01550 }
01551
01552 } else {
01553 hitloc = FindTargetHitLoc(mech, target, &isrear, &iscritical);
01554 }
01555 break;
01556
01557 case PA_KICK:
01558
01559 if (!OkayCritSectS(sect, 2, LOWER_ACTUATOR))
01560 damage = damage / 2;
01561
01562 if (!OkayCritSectS(sect, 1, UPPER_ACTUATOR))
01563 damage = damage / 2;
01564
01565 if (Fallen(target) || MechType(target) != CLASS_MECH) {
01566 hitloc = FindTargetHitLoc(mech, target, &isrear, &iscritical);
01567 } else {
01568
01569 hitgroup = FindAreaHitGroup(mech, target);
01570 if (hitgroup == BACK) {
01571 isrear = 1;
01572 }
01573
01574 if (MechElevation(mech) > MechElevation(target)) {
01575 hitloc = FindPunchLocation(target, hitgroup);
01576 } else {
01577 hitloc = FindKickLocation(target, hitgroup);
01578 }
01579 }
01580 break;
01581
01582 }
01583
01584 if (glance) {
01585 damage = (damage + 1) / 2;
01586 }
01587
01588
01589 MyDamageMech(target, mech, 1, MechPilot(mech), hitloc,
01590 isrear, iscritical, damage, 0);
01591
01592
01593 if (MechType(target) == CLASS_BSUIT && MechSwarmTarget(target) > 0 &&
01594 AttackType != PA_KICK) {
01595 StopSwarming(target, 0);
01596 }
01597
01598
01599 if (MechType(target) == CLASS_MECH && AttackType == PA_KICK) {
01600 if (!MadePilotSkillRoll(target, 0) && !Fallen(target)) {
01601 mech_notify(target, MECHSTARTED,
01602 "The kick knocks you to the ground!");
01603 MechLOSBroadcast(target, "stumbles and falls down!");
01604 MechFalls(target, 1, 0);
01605 }
01606 }
01607
01608 }
01609
01610 #define CHARGE_SECTIONS 6
01611 #define DFA_SECTIONS 6
01612
01613
01614
01615 const int resect[CHARGE_SECTIONS] =
01616 { LARM, RARM, LLEG, RLEG, LTORSO, RTORSO };
01617
01618
01619
01620
01621 int DeathFromAbove(MECH * mech, MECH * target)
01622 {
01623 int baseToHit = 5;
01624 int roll;
01625 int hitGroup;
01626 int hitloc;
01627 int isrear = 0;
01628 int iscritical = 0;
01629 int target_damage;
01630 int mech_damage;
01631 int spread;
01632 int i, tmpi;
01633 char location[50];
01634 MAP *map = getMap(mech->mapindex);
01635
01636
01637 for(i = 0; i < DFA_SECTIONS; i++)
01638 if(SectHasBusyWeap(mech, resect[i])) {
01639 ArmorStringFromIndex(resect[i], location, MechType(mech),
01640 MechMove(mech));
01641 mech_printf(mech, MECHALL,
01642 "You have weapons recycling on your %s.", location);
01643 return 0;
01644 }
01645
01646 DOCHECKMA0((mech->mapindex != target->mapindex),
01647 "Your target is no longer valid.");
01648
01649 #ifdef BT_MOVEMENT_MODES
01650 DOCHECKMA0(Dodging(mech) || MoveModeLock(mech),
01651 "You cannot use physicals while using a special movement mode.");
01652 #endif
01653
01654 DOCHECKMA0(MechSections(mech)[LLEG].recycle ||
01655 MechSections(mech)[RLEG].recycle,
01656 "Your legs are still recovering from your last attack.");
01657 DOCHECKMA0(MechSections(mech)[RARM].recycle ||
01658 MechSections(mech)[LARM].recycle,
01659 "Your arms are still recovering from your last attack.");
01660
01661 DOCHECKMA0(Jumping(target),
01662 "Your target is airborne, you cannot land on it.");
01663
01664 if((MechType(target) == CLASS_VTOL) || (MechType(target) == CLASS_AERO) ||
01665 (MechType(target) == CLASS_DS))
01666 DOCHECKMA0(!Landed(target),
01667 "Your target is airborne, you cannot land on it.");
01668
01669 DOCHECKMA0((MechTeam(mech) == MechTeam(target)) && MapNoFriendlyFire(map),
01670 "Friendly DFA? I don't think so....");
01671 if(mudconf.btech_phys_use_pskill)
01672 baseToHit = FindPilotPiloting(mech);
01673
01674 baseToHit += (HasBoolAdvantage(MechPilot(mech), "melee_specialist") ?
01675 MIN(0,
01676 AttackMovementMods(mech)) -
01677 1 : AttackMovementMods(mech));
01678 baseToHit += TargetMovementMods(mech, target, 0.0);
01679 baseToHit += MechType(target) == CLASS_BSUIT ? 1 : 0;
01680
01681 #ifdef BT_MOVEMENT_MODES
01682 if(Dodging(target))
01683 baseToHit += 2;
01684 #endif
01685
01686 DOCHECKMA0(baseToHit > 12,
01687 tprintf
01688 ("DFA: BTH %d\tYou choose not to attack and land from your jump.",
01689 baseToHit));
01690
01691 roll = Roll();
01692 mech_printf(mech, MECHALL, "DFA: BTH %d\tRoll: %d", baseToHit, roll);
01693
01694 MechStatus(mech) &= ~JUMPING;
01695 MechStatus(mech) &= ~DFA_ATTACK;
01696
01697 if(roll >= baseToHit) {
01698
01699 mech_printf(target, MECHSTARTED,
01700 "DEATH FROM ABOVE!!!\n%s lands on you from above!",
01701 GetMechToMechID(target, mech));
01702 mech_notify(mech, MECHALL, "You land on your target legs first!");
01703 MechLOSBroadcasti(mech, target, "lands on %s!");
01704
01705 hitGroup = FindAreaHitGroup(mech, target);
01706 if(hitGroup == BACK)
01707 isrear = 1;
01708
01709 target_damage = (3 * MechRealTons(mech)) / 10;
01710
01711 if(MechTons(mech) % 10)
01712 target_damage++;
01713
01714 if(HasBoolAdvantage(MechPilot(mech), "melee_specialist"))
01715 target_damage++;
01716
01717 spread = target_damage / 5;
01718
01719 for(i = 0; i < spread; i++) {
01720 if(Fallen(target) || MechType(target) != CLASS_MECH)
01721 hitloc =
01722 FindHitLocation(target, hitGroup, &iscritical, &isrear);
01723 else
01724 hitloc = FindPunchLocation(target, hitGroup);
01725
01726 MyDamageMech(target, mech, 1, MechPilot(mech), hitloc, isrear,
01727 iscritical, 5, 0);
01728 }
01729
01730 if(target_damage % 5) {
01731 if(Fallen(target) || (MechType(target) != CLASS_MECH))
01732 hitloc =
01733 FindHitLocation(target, hitGroup, &iscritical, &isrear);
01734 else
01735 hitloc = FindPunchLocation(target, hitGroup);
01736
01737 MyDamageMech(target, mech, 1, MechPilot(mech), hitloc, isrear,
01738 iscritical, (target_damage % 5), 0);
01739 }
01740
01741 mech_damage = MechTons(mech) / 5;
01742
01743 spread = mech_damage / 5;
01744
01745 for(i = 0; i < spread; i++) {
01746 hitloc = FindKickLocation(mech, FRONT);
01747 MyDamageMech2(mech, mech, 0, -1, hitloc, 0, 0, 5, 0);
01748 }
01749
01750 if(mech_damage % 5) {
01751 hitloc = FindKickLocation(mech, FRONT);
01752 MyDamageMech2(mech, mech, 0, -1, hitloc, 0, 0,
01753 (mech_damage % 5), 0);
01754 }
01755
01756 if(!Fallen(mech)) {
01757 if(!MadePilotSkillRoll(mech, 4)) {
01758 mech_notify(mech, MECHALL,
01759 "Your piloting skill fails and you fall over!!");
01760 MechLOSBroadcast(mech, "stumbles and falls down!");
01761 MechFalls(mech, 1, 0);
01762 }
01763 if(MechType(target) == CLASS_MECH &&
01764 !MadePilotSkillRoll(target, 2)) {
01765 mech_notify(target, MECHSTARTED,
01766 "Your piloting skill fails and you fall over!!");
01767 MechLOSBroadcast(target, "stumbles and falls down!");
01768 MechFalls(target, 1, 0);
01769 }
01770 }
01771
01772 } else {
01773
01774 if(!Fallen(mech)) {
01775 mech_notify(mech, MECHALL,
01776 "You miss your DFA attack and fall on your back!!");
01777 MechLOSBroadcast(mech, "misses DFA and falls down!");
01778 }
01779
01780 mech_damage = MechTons(mech) / 5;
01781 spread = mech_damage / 5;
01782
01783 for(i = 0; i < spread; i++) {
01784 hitloc = FindHitLocation(mech, BACK, &iscritical, &tmpi);
01785 MyDamageMech2(mech, mech, 0, -1, hitloc, 1, iscritical, 5, 0);
01786 }
01787
01788 if(mech_damage % 5) {
01789 hitloc = FindHitLocation(mech, BACK, &iscritical, &tmpi);
01790 MyDamageMech2(mech, mech, 0, -1, hitloc, 1, iscritical,
01791 (mech_damage % 5), 0);
01792 }
01793
01794
01795 if(!MadePilotSkillRoll(mech, 2)) {
01796 mech_notify(mech, MECHALL,
01797 "You take personal injury from the fall!");
01798 headhitmwdamage(mech, mech, 1);
01799 }
01800
01801 MechSpeed(mech) = 0.0;
01802 MechDesiredSpeed(mech) = 0.0;
01803
01804 MakeMechFall(mech);
01805 MechZ(mech) = MechElevation(mech);
01806 MechFZ(mech) = MechZ(mech) * ZSCALE;
01807
01808 if(MechZ(mech) < 0)
01809 MechFloods(mech);
01810
01811 }
01812
01813 for(i = 0; i < DFA_SECTIONS; i++)
01814 SetRecycleLimb(mech, resect[i], PHYSICAL_RECYCLE_TIME);
01815
01816 return 1;
01817 }
01818
01819
01820
01821
01822 void ChargeMech(MECH * mech, MECH * target)
01823 {
01824 int baseToHit = 5;
01825 int roll;
01826 int hitGroup;
01827 int hitloc;
01828 int isrear = 0;
01829 int iscritical = 0;
01830 int target_damage;
01831 int mech_damage;
01832 int received_damage;
01833 int inflicted_damage;
01834 int spread;
01835 int i;
01836 int mech_charge;
01837 int target_charge;
01838 int mech_baseToHit;
01839 int targ_baseToHit;
01840 int mech_roll;
01841 int targ_roll;
01842 int done = 0;
01843 char location[50];
01844 int ts, iwa;
01845 char emit_buff[LBUF_SIZE];
01846
01847
01848 if(MechChargeTarget(target) == mech->mynum) {
01849
01850 mech_charge = 1;
01851 target_charge = 1;
01852
01853
01854 done = 0;
01855 for(i = 0; i < CHARGE_SECTIONS && !done; i++) {
01856 if(SectHasBusyWeap(mech, resect[i])) {
01857 ArmorStringFromIndex(resect[i], location, MechType(mech),
01858 MechMove(mech));
01859 mech_printf(mech, MECHALL,
01860 "You have weapons recycling on your %s.",
01861 location);
01862 mech_charge = 0;
01863 done = 1;
01864 }
01865 }
01866
01867
01868 done = 0;
01869 for(i = 0; i < CHARGE_SECTIONS && !done; i++) {
01870 if(SectHasBusyWeap(target, resect[i])) {
01871 ArmorStringFromIndex(resect[i], location, MechType(target),
01872 MechMove(target));
01873 mech_printf(target, MECHALL,
01874 "You have weapons recycling on your %s.",
01875 location);
01876 target_charge = 0;
01877 done = 1;
01878 }
01879 }
01880
01881
01882 if(!Started(target) || Uncon(target) || Blinded(target))
01883 target_charge = 0;
01884
01885 if(!Started(mech) || Uncon(mech) || Blinded(mech))
01886 mech_charge = 0;
01887
01888
01889 if(MechSpeed(mech) < MP1) {
01890 mech_notify(mech, MECHALL,
01891 "You aren't moving fast enough to charge.");
01892 mech_charge = 0;
01893 }
01894
01895
01896 if(MechSpeed(target) < MP1) {
01897 mech_notify(target, MECHALL,
01898 "You aren't moving fast enough to charge.");
01899 target_charge = 0;
01900 }
01901
01902
01903 if(MechType(mech) == CLASS_MECH) {
01904
01905 if(MechSections(mech)[LLEG].recycle ||
01906 MechSections(mech)[RLEG].recycle) {
01907 mech_notify(mech, MECHALL,
01908 "Your legs are still recovering from your last attack.");
01909 mech_charge = 0;
01910 }
01911
01912 if(MechSections(mech)[RARM].recycle ||
01913 MechSections(mech)[LARM].recycle) {
01914 mech_notify(mech, MECHALL,
01915 "Your arms are still recovering from your last attack.");
01916 mech_charge = 0;
01917 }
01918 } else {
01919
01920 if(MechSections(mech)[FSIDE].recycle) {
01921 mech_notify(mech, MECHALL,
01922 "You are still recovering from your last attack!");
01923 mech_charge = 0;
01924 }
01925 }
01926
01927
01928 if(MechType(target) == CLASS_MECH) {
01929
01930 if(MechSections(target)[LLEG].recycle ||
01931 MechSections(target)[RLEG].recycle) {
01932 mech_notify(target, MECHALL,
01933 "Your legs are still recovering from your last attack.");
01934 target_charge = 0;
01935 }
01936
01937 if(MechSections(target)[RARM].recycle ||
01938 MechSections(target)[LARM].recycle) {
01939 mech_notify(target, MECHALL,
01940 "Your arms are still recovering from your last attack.");
01941 target_charge = 0;
01942 }
01943 } else {
01944
01945 if(MechSections(target)[FSIDE].recycle) {
01946 mech_notify(target, MECHALL,
01947 "You are still recovering from your last attack!");
01948 target_charge = 0;
01949 }
01950 }
01951
01952
01953 if(Jumping(target)) {
01954 mech_notify(mech, MECHALL,
01955 "Your target is jumping, you charge underneath it.");
01956 mech_notify(target, MECHALL,
01957 "You can't charge while jumping, try death from above.");
01958 mech_charge = 0;
01959 target_charge = 0;
01960 }
01961
01962
01963 if(Jumping(mech)) {
01964 mech_notify(target, MECHALL,
01965 "Your target is jumping, you charge underneath it.");
01966 mech_notify(mech, MECHALL,
01967 "You can't charge while jumping, try death from above.");
01968 mech_charge = 0;
01969 target_charge = 0;
01970 }
01971
01972
01973 if(Fallen(target) && (MechType(mech) != CLASS_VEH_GROUND)) {
01974 mech_notify(mech, MECHALL,
01975 "Your target's too low for you to charge it!");
01976 mech_charge = 0;
01977 }
01978
01979
01980
01981
01982 if(Fallen(mech) && (MechType(target) != CLASS_VEH_GROUND)) {
01983 mech_notify(target, MECHALL,
01984 "Your target's too low for you to charge it!");
01985 target_charge = 0;
01986 }
01987
01988
01989 if((MechType(target) == CLASS_MECH) && (MechType(mech) != CLASS_MECH)) {
01990 mech_notify(target, MECHALL, "You can only charge mechs!");
01991 target_charge = 0;
01992 }
01993
01994
01995 if((MechType(mech) == CLASS_MECH) && (MechType(target) != CLASS_MECH)) {
01996 mech_notify(mech, MECHALL, "You can only charge mechs!");
01997 mech_charge = 0;
01998 }
01999
02000
02001 if((MechType(target) == CLASS_VEH_GROUND) &&
02002 ((MechType(mech) != CLASS_MECH) &&
02003 (MechType(mech) != CLASS_VEH_GROUND))) {
02004 mech_notify(target, MECHALL,
02005 "You can only charge mechs and tanks!");
02006 target_charge = 0;
02007 }
02008
02009
02010 if((MechType(mech) == CLASS_VEH_GROUND) &&
02011 ((MechType(target) != CLASS_MECH) &&
02012 (MechType(target) != CLASS_VEH_GROUND))) {
02013 mech_notify(mech, MECHALL,
02014 "You can only charge mechs and tanks!");
02015 mech_charge = 0;
02016 }
02017
02018
02019 if(CrewStunned(mech)) {
02020 mech_notify(mech, MECHALL, "You are too stunned to ram!");
02021 mech_charge = 0;
02022 }
02023
02024 if(CrewStunned(target)) {
02025 mech_notify(target, MECHALL, "You are too stunned to ram!");
02026 target_charge = 0;
02027 }
02028
02029
02030 if(UnjammingTurret(mech)) {
02031 mech_notify(mech, MECHALL,
02032 "You are too busy unjamming your turret!");
02033 mech_charge = 0;
02034 }
02035
02036 if(UnjammingTurret(target)) {
02037 mech_notify(mech, MECHALL,
02038 "You are too busy unjamming your turret!");
02039 target_charge = 0;
02040 }
02041
02042
02043 ts = MechStatus(mech) & (TORSO_LEFT | TORSO_RIGHT);
02044 MechStatus(mech) &= ~ts;
02045 if(!(InWeaponArc(mech, MechFX(target), MechFY(target)) & FORWARDARC)) {
02046 mech_notify(mech, MECHALL,
02047 "Your charge target is not in your forward arc and you are unable to charge it.");
02048 mech_charge = 0;
02049 }
02050 MechStatus(mech) |= ts;
02051
02052 ts = MechStatus(target) & (TORSO_LEFT | TORSO_RIGHT);
02053 MechStatus(mech) &= ~ts;
02054 if(!(InWeaponArc(target, MechFX(mech), MechFY(mech)) & FORWARDARC)) {
02055 mech_notify(target, MECHALL,
02056 "Your charge target is not in your forward arc and you are unable to charge it.");
02057 target_charge = 0;
02058 }
02059 MechStatus(mech) |= ts;
02060
02061
02062 if(mudconf.btech_newcharge)
02063 target_damage = (((((float)
02064 MechChargeDistance(mech)) * MP1) -
02065 MechSpeed(target) * cos((MechFacing(mech) -
02066 MechFacing(target)) *
02067 (M_PI / 180.))) *
02068 MP_PER_KPH) * (MechRealTons(mech) + 5) / 10;
02069 else
02070 target_damage =
02071 ((MechSpeed(mech) -
02072 MechSpeed(target) * cos((MechFacing(mech) -
02073 MechFacing(target)) * (M_PI /
02074 180.))) *
02075 MP_PER_KPH) * (MechRealTons(mech) + 5) / 10;
02076
02077 if(HasBoolAdvantage(MechPilot(mech), "melee_specialist"))
02078 target_damage++;
02079
02080
02081 if(target_damage <= 0) {
02082 mech_notify(mech, MECHPILOT,
02083 "Your target pulls away from you and you are unable to charge it.");
02084 mech_charge = 0;
02085 }
02086
02087
02088 if(mudconf.btech_newcharge)
02089 mech_damage = (((((float)
02090 MechChargeDistance(target)) * MP1) -
02091 MechSpeed(mech) * cos((MechFacing(target) -
02092 MechFacing(mech)) * (M_PI /
02093 180.)))
02094 * MP_PER_KPH) * (MechRealTons(target) + 5) / 10;
02095 else
02096 mech_damage =
02097 ((MechSpeed(target) -
02098 MechSpeed(mech) * cos((MechFacing(target) -
02099 MechFacing(mech)) * (M_PI / 180.))) *
02100 MP_PER_KPH) * (MechRealTons(target) + 5) / 10;
02101
02102 if(HasBoolAdvantage(MechPilot(target), "melee_specialist"))
02103 mech_damage++;
02104
02105
02106 if(mech_damage <= 0) {
02107 mech_notify(target, MECHPILOT,
02108 "Your target pulls away from you and you are unable to charge it.");
02109 target_charge = 0;
02110 }
02111
02112
02113 mech_baseToHit = 5;
02114 mech_baseToHit +=
02115 FindPilotPiloting(mech) - FindSPilotPiloting(target);
02116
02117 mech_baseToHit +=
02118 (HasBoolAdvantage(MechPilot(mech), "melee_specialist") ?
02119 MIN(0, AttackMovementMods(mech) - 1) : AttackMovementMods(mech));
02120
02121 mech_baseToHit += TargetMovementMods(mech, target, 0.0);
02122
02123 #ifdef BT_MOVEMENT_MODES
02124 if(Dodging(target))
02125 mech_baseToHit += 2;
02126 #endif
02127
02128
02129 targ_baseToHit = 5;
02130 targ_baseToHit +=
02131 FindPilotPiloting(target) - FindSPilotPiloting(mech);
02132
02133 targ_baseToHit +=
02134 (HasBoolAdvantage(MechPilot(target), "melee_specialist") ?
02135 MIN(0,
02136 AttackMovementMods(target) -
02137 1) : AttackMovementMods(target));
02138
02139 targ_baseToHit += TargetMovementMods(target, mech, 0.0);
02140
02141 #ifdef BT_MOVEMENT_MODES
02142 if(Dodging(mech))
02143 targ_baseToHit += 2;
02144 #endif
02145
02146
02147 if(mech_charge)
02148 if(mech_baseToHit > 12) {
02149 mech_printf(mech, MECHALL,
02150 "Charge: BTH %d\tYou choose not to charge.",
02151 mech_baseToHit);
02152 mech_charge = 0;
02153 }
02154
02155 if(target_charge)
02156 if(targ_baseToHit > 12) {
02157 mech_printf(target, MECHALL,
02158 "Charge: BTH %d\tYou choose not to charge.",
02159 targ_baseToHit);
02160 target_charge = 0;
02161 }
02162
02163
02164 if(!mech_charge && !target_charge) {
02165
02166
02167 MechChargeTarget(target) = -1;
02168 MechChargeTimer(target) = 0;
02169 MechChargeDistance(target) = 0;
02170 return;
02171 }
02172
02173
02174 mech_roll = Roll();
02175 targ_roll = Roll();
02176
02177 if(mech_charge)
02178 mech_printf(mech, MECHALL,
02179 "Charge: BTH %d\tRoll: %d", mech_baseToHit,
02180 mech_roll);
02181
02182 if(target_charge)
02183 mech_printf(target, MECHALL,
02184 "Charge: BTH %d\tRoll: %d", targ_baseToHit,
02185 targ_roll);
02186
02187
02188 if(mech_charge && mech_roll >= mech_baseToHit) {
02189
02190 mech_printf(target, MECHALL,
02191 "CRASH!!!\n%s charges into you!",
02192 GetMechToMechID(target, mech));
02193 mech_notify(mech, MECHALL,
02194 "SMASH!!! You crash into your target!");
02195 hitGroup = FindAreaHitGroup(mech, target);
02196 isrear = (hitGroup == BACK);
02197
02198
02199 inflicted_damage = target_damage;
02200 spread = target_damage / 5;
02201
02202 for(i = 0; i < spread; i++) {
02203 hitloc =
02204 FindHitLocation(target, hitGroup, &iscritical, &isrear);
02205 MyDamageMech(target, mech, 1, MechPilot(mech), hitloc,
02206 isrear, iscritical, 5, 0);
02207 }
02208
02209 if(target_damage % 5) {
02210 hitloc =
02211 FindHitLocation(target, hitGroup, &iscritical, &isrear);
02212 MyDamageMech(target, mech, 1, MechPilot(mech), hitloc,
02213 isrear, iscritical, (target_damage % 5), 0);
02214 }
02215
02216 hitGroup = FindAreaHitGroup(target, mech);
02217 isrear = (hitGroup == BACK);
02218
02219
02220
02221 if(mudconf.btech_newcharge && mudconf.btech_tl3_charge)
02222 target_damage =
02223 (((((float) MechChargeDistance(mech)) * MP1) -
02224 MechSpeed(target) *
02225 cos((MechFacing(mech) -
02226 MechFacing(target)) * (M_PI / 180.))) *
02227 MP_PER_KPH) * (MechRealTons(mech) + 5) / 20;
02228 else
02229 target_damage = (MechRealTons(target) + 5) / 10;
02230
02231
02232 received_damage = target_damage;
02233 spread = target_damage / 5;
02234
02235 for(i = 0; i < spread; i++) {
02236 hitloc =
02237 FindHitLocation(mech, hitGroup, &iscritical, &isrear);
02238 MyDamageMech2(mech, mech, 0, -1, hitloc, isrear,
02239 iscritical, 5, 0);
02240 }
02241
02242 if(target_damage % 5) {
02243 hitloc =
02244 FindHitLocation(mech, hitGroup, &iscritical, &isrear);
02245 MyDamageMech2(mech, mech, 0, -1, hitloc, isrear,
02246 iscritical, (target_damage % 5), 0);
02247 }
02248
02249
02250 MechSpeed(mech) = 0;
02251 MechDesiredSpeed(mech) = 0;
02252
02253
02254 snprintf(emit_buff, LBUF_SIZE, "#%i charges #%i (%i/%i) Distance:"
02255 " %.2f DI: %i DR: %i", mech->mynum, target->mynum,
02256 mech_baseToHit, mech_roll, MechChargeDistance(mech),
02257 inflicted_damage, received_damage);
02258 SendDebug(emit_buff);
02259
02260
02261 if(MechType(mech) == CLASS_MECH && !MadePilotSkillRoll(mech, 2)) {
02262 mech_notify(mech, MECHALL,
02263 "Your piloting skill fails and you fall over!!");
02264 MechFalls(mech, 1, 1);
02265 }
02266
02267 if(MechType(mech) == CLASS_MECH && !MadePilotSkillRoll(target, 2)) {
02268 mech_notify(target, MECHALL,
02269 "Your piloting skill fails and you fall over!!");
02270 MechFalls(target, 1, 1);
02271 }
02272 }
02273
02274
02275 if(target_charge && targ_roll >= targ_baseToHit) {
02276
02277 mech_printf(mech, MECHALL,
02278 "CRASH!!!\n%s charges into you!",
02279 GetMechToMechID(mech, target));
02280 mech_notify(target, MECHALL,
02281 "SMASH!!! You crash into your target!");
02282 hitGroup = FindAreaHitGroup(target, mech);
02283 isrear = (hitGroup == BACK);
02284
02285
02286 inflicted_damage = mech_damage;
02287 spread = mech_damage / 5;
02288
02289 for(i = 0; i < spread; i++) {
02290 hitloc =
02291 FindHitLocation(mech, hitGroup, &iscritical, &isrear);
02292 MyDamageMech(mech, target, 1, MechPilot(target), hitloc,
02293 isrear, iscritical, 5, 0);
02294 }
02295
02296 if(mech_damage % 5) {
02297 hitloc =
02298 FindHitLocation(mech, hitGroup, &iscritical, &isrear);
02299 MyDamageMech(mech, target, 1, MechPilot(target), hitloc,
02300 isrear, iscritical, (mech_damage % 5), 0);
02301 }
02302
02303 hitGroup = FindAreaHitGroup(mech, target);
02304 isrear = (hitGroup == BACK);
02305
02306
02307
02308 if(mudconf.btech_newcharge && mudconf.btech_tl3_charge)
02309 target_damage =
02310 (((((float) MechChargeDistance(target)) * MP1) -
02311 MechSpeed(mech) *
02312 cos((MechFacing(target) -
02313 MechFacing(mech)) * (M_PI / 180.))) * MP_PER_KPH) *
02314 (MechRealTons(mech) + 5) / 20;
02315 else
02316 target_damage = (MechRealTons(mech) + 5) / 10;
02317
02318
02319 received_damage = target_damage;
02320 spread = target_damage / 5;
02321
02322 for(i = 0; i < spread; i++) {
02323 hitloc =
02324 FindHitLocation(target, hitGroup, &iscritical, &isrear);
02325 MyDamageMech2(target, target, 0, -1, hitloc, isrear,
02326 iscritical, 5, 0);
02327 }
02328
02329 if(mech_damage % 5) {
02330 hitloc =
02331 FindHitLocation(target, hitGroup, &iscritical, &isrear);
02332 MyDamageMech2(target, target, 0, -1, hitloc, isrear,
02333 iscritical, (mech_damage % 5), 0);
02334 }
02335
02336
02337 MechSpeed(target) = 0;
02338 MechDesiredSpeed(target) = 0;
02339
02340
02341 snprintf(emit_buff, LBUF_SIZE, "#%i charges #%i (%i/%i) Distance:"
02342 " %.2f DI: %i DR: %i", target->mynum, mech->mynum,
02343 targ_baseToHit, targ_roll, MechChargeDistance(target),
02344 inflicted_damage, received_damage);
02345 SendDebug(emit_buff);
02346
02347 if(MechType(mech) == CLASS_MECH && !MadePilotSkillRoll(mech, 2)) {
02348 mech_notify(mech, MECHALL,
02349 "Your piloting skill fails and you fall over!!");
02350 MechFalls(mech, 1, 1);
02351 }
02352 if(MechType(target) == CLASS_MECH
02353 && !MadePilotSkillRoll(target, 2)) {
02354 mech_notify(target, MECHALL,
02355 "Your piloting skill fails and you fall over!!");
02356 MechFalls(target, 1, 1);
02357 }
02358 }
02359
02360
02361 if(MechType(mech) == CLASS_MECH) {
02362 for(i = 0; i < CHARGE_SECTIONS; i++)
02363 SetRecycleLimb(mech, resect[i], PHYSICAL_RECYCLE_TIME);
02364 } else {
02365 SetRecycleLimb(mech, FSIDE, PHYSICAL_RECYCLE_TIME);
02366 SetRecycleLimb(mech, TURRET, PHYSICAL_RECYCLE_TIME);
02367 }
02368
02369 if(MechType(target) == CLASS_MECH) {
02370 for(i = 0; i < CHARGE_SECTIONS; i++)
02371 SetRecycleLimb(target, resect[i], PHYSICAL_RECYCLE_TIME);
02372 } else {
02373 SetRecycleLimb(target, FSIDE, PHYSICAL_RECYCLE_TIME);
02374 SetRecycleLimb(target, TURRET, PHYSICAL_RECYCLE_TIME);
02375 }
02376
02377
02378
02379 MechChargeTarget(target) = -1;
02380 MechChargeTimer(target) = 0;
02381 MechChargeDistance(target) = 0;
02382 return;
02383 }
02384
02385
02386 for(i = 0; i < CHARGE_SECTIONS; i++) {
02387 if(SectHasBusyWeap(mech, i)) {
02388 ArmorStringFromIndex(i, location, MechType(mech), MechMove(mech));
02389 mech_printf(mech, MECHALL,
02390 "You have weapons recycling on your %s.", location);
02391 return;
02392 }
02393 }
02394
02395
02396 DOCHECKMA(MechSpeed(mech) < MP1,
02397 "You aren't moving fast enough to charge.");
02398
02399
02400 if(MechType(mech) == CLASS_MECH) {
02401 DOCHECKMA(MechSections(mech)[LLEG].recycle ||
02402 MechSections(mech)[RLEG].recycle,
02403 "Your legs are still recovering from your last attack.");
02404 DOCHECKMA(MechSections(mech)[RARM].recycle ||
02405 MechSections(mech)[LARM].recycle,
02406 "Your arms are still recovering from your last attack.");
02407 } else {
02408 DOCHECKMA(MechSections(mech)[FSIDE].recycle,
02409 "You are still recovering from your last attack!");
02410 }
02411
02412
02413 DOCHECKMA(Jumping(target),
02414 "Your target is jumping, you charge underneath it.");
02415 DOCHECKMA(Jumping(mech),
02416 "You can't charge while jumping, try death from above.");
02417
02418
02419 DOCHECKMA(Fallen(target) &&
02420 (MechType(mech) != CLASS_VEH_GROUND),
02421 "Your target's too low for you to charge it!");
02422
02423
02424 DOCHECKMA((MechType(mech) == CLASS_MECH) &&
02425 (MechType(target) != CLASS_MECH), "You can only charge mechs!");
02426
02427
02428 DOCHECKMA((MechType(mech) == CLASS_VEH_GROUND) &&
02429 ((MechType(target) != CLASS_MECH) &&
02430 (MechType(target) != CLASS_VEH_GROUND)),
02431 "You can only charge mechs and tanks!");
02432
02433
02434 ts = MechStatus(mech) & (TORSO_LEFT | TORSO_RIGHT);
02435 MechStatus(mech) &= ~ts;
02436 iwa = InWeaponArc(mech, MechFX(target), MechFY(target));
02437 MechStatus(mech) |= ts;
02438 DOCHECKMA(!(iwa & FORWARDARC),
02439 "Your charge target is not in your forward arc and you are unable to charge it.");
02440
02441
02442 if(mudconf.btech_newcharge)
02443 target_damage = (((((float)
02444 MechChargeDistance(mech)) * MP1) -
02445 MechSpeed(target) * cos((MechFacing(mech) -
02446 MechFacing(target)) *
02447 (M_PI / 180.))) *
02448 MP_PER_KPH) * (MechRealTons(mech) + 5) / 10 + 1;
02449 else
02450 target_damage =
02451 ((MechSpeed(mech) - MechSpeed(target) * cos((MechFacing(mech) -
02452 MechFacing(target)) *
02453 (M_PI / 180.))) *
02454 MP_PER_KPH) * (MechRealTons(mech) + 5) / 10 + 1;
02455
02456 if(HasBoolAdvantage(MechPilot(mech), "melee_specialist"))
02457 target_damage++;
02458
02459
02460 DOCHECKMP(target_damage <= 0,
02461 "Your target pulls away from you and you are unable to charge it.");
02462
02463
02464 baseToHit += FindPilotPiloting(mech) - FindSPilotPiloting(target);
02465
02466 baseToHit += (HasBoolAdvantage(MechPilot(mech), "melee_specialist") ?
02467 MIN(0,
02468 AttackMovementMods(mech) -
02469 1) : AttackMovementMods(mech));
02470
02471 baseToHit += TargetMovementMods(mech, target, 0.0);
02472
02473 #ifdef BT_MOVEMENT_MODES
02474 if(Dodging(target))
02475 baseToHit += 2;
02476 #endif
02477
02478 DOCHECKMA(baseToHit > 12,
02479 tprintf("Charge: BTH %d\tYou choose not to charge.",
02480 baseToHit));
02481
02482
02483 roll = Roll();
02484 mech_printf(mech, MECHALL, "Charge: BTH %d\tRoll: %d", baseToHit, roll);
02485
02486
02487 if(roll >= baseToHit) {
02488
02489 MechLOSBroadcasti(mech, target, tprintf("%ss %%s!",
02490 MechType(mech) ==
02491 CLASS_MECH ? "charge" :
02492 "ram"));
02493 mech_printf(target, MECHSTARTED, "CRASH!!!\n%s %ss into you!",
02494 GetMechToMechID(target, mech),
02495 MechType(mech) == CLASS_MECH ? "charge" : "ram");
02496 mech_notify(mech, MECHALL, "SMASH!!! You crash into your target!");
02497 hitGroup = FindAreaHitGroup(mech, target);
02498
02499 if(hitGroup == BACK)
02500 isrear = 1;
02501 else
02502 isrear = 0;
02503
02504
02505 inflicted_damage = target_damage;
02506 spread = target_damage / 5;
02507
02508 for(i = 0; i < spread; i++) {
02509 hitloc = FindHitLocation(target, hitGroup, &iscritical, &isrear);
02510 MyDamageMech(target, mech, 1, MechPilot(mech), hitloc, isrear,
02511 iscritical, 5, 0);
02512 }
02513
02514 if(target_damage % 5) {
02515 hitloc = FindHitLocation(target, hitGroup, &iscritical, &isrear);
02516 MyDamageMech(target, mech, 1, MechPilot(mech), hitloc, isrear,
02517 iscritical, (target_damage % 5), 0);
02518 }
02519
02520 hitGroup = FindAreaHitGroup(target, mech);
02521 isrear = (hitGroup == BACK);
02522
02523
02524 if(mudconf.btech_newcharge && mudconf.btech_tl3_charge)
02525 mech_damage =
02526 (((((float) MechChargeDistance(mech)) * MP1) -
02527 MechSpeed(target) *
02528 cos((MechFacing(mech) -
02529 MechFacing(target)) * (M_PI / 180.))) * MP_PER_KPH) *
02530 (MechRealTons(target) + 5) / 20;
02531 else
02532 mech_damage = (MechRealTons(target) + 5) / 10;
02533
02534
02535 received_damage = mech_damage;
02536 spread = mech_damage / 5;
02537
02538 for(i = 0; i < spread; i++) {
02539 hitloc = FindHitLocation(mech, hitGroup, &iscritical, &isrear);
02540 MyDamageMech2(mech, mech, 0, -1, hitloc, isrear, iscritical, 5,
02541 0);
02542 }
02543
02544 if(mech_damage % 5) {
02545 hitloc = FindHitLocation(mech, hitGroup, &iscritical, &isrear);
02546 MyDamageMech2(mech, mech, 0, -1, hitloc, isrear, iscritical,
02547 (mech_damage % 5), 0);
02548 }
02549
02550
02551 if(MechType(mech) == CLASS_MECH && !MadePilotSkillRoll(mech, 2)) {
02552 mech_notify(mech, MECHALL,
02553 "Your piloting skill fails and you fall over!!");
02554 MechFalls(mech, 1, 1);
02555 }
02556
02557
02558 if(MechType(target) == CLASS_MECH && !MadePilotSkillRoll(target, 2)) {
02559 mech_notify(target, MECHSTARTED,
02560 "Your piloting skill fails and you fall over!!");
02561 MechFalls(target, 1, 1);
02562 }
02563
02564
02565 MechSpeed(mech) = 0;
02566 MechDesiredSpeed(mech) = 0;
02567
02568
02569 snprintf(emit_buff, LBUF_SIZE, "#%i charges #%i (%i/%i) Distance:"
02570 " %.2f DI: %i DR: %i", mech->mynum, target->mynum, baseToHit,
02571 roll, MechChargeDistance(mech), inflicted_damage,
02572 received_damage);
02573 SendDebug(emit_buff);
02574
02575 }
02576
02577
02578 if(MechType(mech) == CLASS_MECH) {
02579 for(i = 0; i < CHARGE_SECTIONS; i++)
02580 SetRecycleLimb(mech, resect[i], PHYSICAL_RECYCLE_TIME);
02581 } else {
02582 SetRecycleLimb(mech, FSIDE, PHYSICAL_RECYCLE_TIME);
02583 SetRecycleLimb(mech, TURRET, PHYSICAL_RECYCLE_TIME);
02584 }
02585 return;
02586 }
02587
02588
02589
02590
02591 int checkGrabClubLocation(MECH * mech, int section, int emit)
02592 {
02593 int tCanGrab = 1;
02594 char buf[100];
02595 char location[20];
02596
02597 ArmorStringFromIndex(section, location, MechType(mech), MechMove(mech));
02598
02599 if(SectIsDestroyed(mech, section)) {
02600 sprintf(buf, "Your %s is destroyed.", location);
02601 tCanGrab = 0;
02602 } else if(!OkayCritSectS(section, 3, HAND_OR_FOOT_ACTUATOR)) {
02603 sprintf(buf, "Your %s's hand actuator is destroyed or missing.",
02604 location);
02605 tCanGrab = 0;
02606 } else if(!OkayCritSectS(section, 0, SHOULDER_OR_HIP)) {
02607 sprintf(buf,
02608 "Your %s's shoulder actuator is destroyed or missing.",
02609 location);
02610 tCanGrab = 0;
02611 } else if(SectHasBusyWeap(mech, section)) {
02612 sprintf(buf, "Your %s is still recovering from it's last attack.",
02613 location);
02614 tCanGrab = 0;
02615 }
02616
02617 if(!tCanGrab && emit)
02618 mech_notify(mech, MECHALL, buf);
02619
02620 return tCanGrab;
02621 }
02622
02623
02624
02625
02626 void mech_grabclub(dbref player, void *data, char *buffer)
02627 {
02628 MECH *mech = (MECH *) data;
02629 int wcArgs = 0;
02630 int location = 0;
02631 char *args[1];
02632 char locname[20];
02633
02634 cch(MECH_USUALO);
02635
02636 wcArgs = mech_parseattributes(buffer, args, 1);
02637
02638
02639 if(wcArgs >= 1 && toupper(args[0][0]) == '-') {
02640 if((MechSections(mech)[LARM].specials & CARRYING_CLUB) ||
02641 (MechSections(mech)[RARM].specials & CARRYING_CLUB)) {
02642 DropClub(mech);
02643 } else {
02644 mech_notify(mech, MECHALL,
02645 "You aren't currently carrying a club.");
02646 }
02647 return;
02648 }
02649
02650 DOCHECKMA(MechIsQuad(mech), "Quads can't carry a club.");
02651 DOCHECKMA(Fallen(mech),
02652 "You can't grab a club while lying flat on your face.");
02653 DOCHECKMA(Jumping(mech), "You can't grab a club while jumping!");
02654 DOCHECKMA(OODing(mech), "Your rapid descent prevents that.");
02655 DOCHECKMA(UnJammingAmmo(mech), "You are too busy unjamming a weapon!");
02656 DOCHECKMA(RemovingPods(mech), "You are too busy removing iNARC pods!");
02657
02658
02659 DOCHECKMA(have_axe(mech, LARM) || have_axe(mech, RARM),
02660 "You can not grab a club if you carry an axe.");
02661 DOCHECKMA(have_sword(mech, LARM) || have_sword(mech, RARM),
02662 "You can not grab a club if you carry a sword.");
02663 DOCHECKMA(have_mace(mech, LARM) || have_mace(mech, RARM),
02664 "You can not grab a club if you carry an mace.");
02665
02666 if(wcArgs == 0) {
02667 if(checkGrabClubLocation(mech, LARM, 0))
02668 location = LARM;
02669 else if(checkGrabClubLocation(mech, RARM, 0))
02670 location = RARM;
02671 else {
02672 mech_notify(mech, MECHALL,
02673 "You don't have a free arm with a working hand actuator!");
02674 return;
02675 }
02676 } else {
02677
02678
02679 switch (toupper(args[0][0])) {
02680 case 'R':
02681 location = RARM;
02682 break;
02683 case 'L':
02684 location = LARM;
02685 break;
02686 default:
02687 mech_notify(mech, MECHALL, "Invalid option for 'grabclub'");
02688 return;
02689 }
02690
02691
02692 if(!checkGrabClubLocation(mech, location, 1))
02693 return;
02694 }
02695
02696 DOCHECKMA(CarryingClub(mech), "You're already carrying a club.");
02697 DOCHECKMA(MechRTerrain(mech) != HEAVY_FOREST &&
02698 MechRTerrain(mech) != LIGHT_FOREST,
02699 "There don't appear to be any trees within grabbing distance.");
02700
02701 ArmorStringFromIndex(location, locname, MechType(mech), MechMove(mech));
02702
02703 MechLOSBroadcast(mech,
02704 "reaches down and yanks a tree out of the ground!");
02705 mech_printf(mech, MECHALL,
02706 "You reach down and yank a tree out of the ground with your %s.",
02707 locname);
02708
02709
02710 MechSections(mech)[location].specials |= CARRYING_CLUB;
02711 SetRecycleLimb(mech, location, PHYSICAL_RECYCLE_TIME);
02712 }