Beispiel #1
0
void check_stagger_event(EVENT * event)
{
    MECH *mech = (MECH *) event->data;	/* get the mech */

    SendDebug(tprintf("Triggered stagger check for %d.", mech->mynum));

    if ((StaggerLevel(mech) < 1) || Fallen(mech) ||
	(MechType(mech) != CLASS_MECH)) {
	StopStaggerCheck(mech);
	return;
    }

    if (Jumping(mech)) {
	return;
    }

    mech_notify(mech, MECHALL, "You stagger from the damage!");
    if (!MadePilotSkillRoll(mech, calcStaggerBTHMod(mech))) {
	mech_notify(mech, MECHALL,
	    "You loose the battle with gravity and tumble over!!");
	MechLOSBroadcast(mech, "tumbles over, staggered by the damage!");
	MechFalls(mech, 1, 0);
    }

    StopStaggerCheck(mech);
}
Beispiel #2
0
static void mech_srec_event(MUXEVENT * e)
{
	MECH *mech = (MECH *) e->data;
	int val = (int) e->data2;
	int vt = val / 256;

	switch (vt) {
	case 0:
		MechTacRange(mech) = val;
		if(!Destroyed(mech))
			mech_notify(mech, MECHALL,
						"Your tactical scanners are operational again.");
		break;
	case 1:
		MechLRSRange(mech) = val;
		if(!Destroyed(mech))
			mech_notify(mech, MECHALL,
						"Your long-range scanners are operational again.");
		break;
	case 2:
		MechScanRange(mech) = val;
		if(!Destroyed(mech))
			mech_notify(mech, MECHALL,
						"Your scanners are operational again.");
		break;
	}
}
Beispiel #3
0
void sendNetworkMessage(dbref player, MECH * mech, char *msg, int tIsC3)
{
	int i;
	MECH *otherMech;
	const char *c = GetMechID(mech);
	char buf[LBUF_SIZE];
	int networkSize;
	dbref myNetwork[C3_NETWORK_SIZE];

	buildTempNetwork(mech, myNetwork, &networkSize, 1, 1, 1, tIsC3);

	for(i = 0; i < networkSize; i++) {
		otherMech = getMechInTempNetwork(i, myNetwork, networkSize);

		if(!otherMech)
			continue;

		if(!Good_obj(otherMech->mynum))
			continue;

		sprintf(buf, "%%ch%s/%s: %s%%cn", (tIsC3 ? "C3" : "C3i"), c, msg);
		mech_notify(otherMech, MECHALL, buf);
	}

	sprintf(buf, "%%ch%s/You: %s%%cn", (tIsC3 ? "C3" : "C3i"), msg);
	mech_notify(mech, MECHALL, buf);
}
Beispiel #4
0
static int Leave_DS_Bay(MAP * map, MECH * ds, MECH * mech, dbref frombay)
{
	MECH *car = NULL;

	StopBSuitSwarmers(FindObjectsData(mech->mapindex), mech, 1);
	MechLOSBroadcast(mech, "has left the bay.");
	/* We escape confines of the bay to open air/land! */
	mech_Rsetmapindex(GOD, (void *) mech, tprintf("%d", ds->mapindex));
	if(MechCarrying(mech) > 0)
		car = getMech(MechCarrying(mech));
	if(car)
		mech_Rsetmapindex(GOD, (void *) car, tprintf("%d", ds->mapindex));
	DOCHECKMA0(mech->mapindex == map->mynum,
			   "Fatal error: Unable to find the map 'ship is on.");
	loud_teleport(mech->mynum, mech->mapindex);
	if(car)
		loud_teleport(car->mynum, mech->mapindex);
	mech_notify(mech, MECHALL, "You have left the bay.");
	DS_Place(ds, mech, frombay);
	if(car)
		MirrorPosition(mech, car, 0);
	MechLOSBroadcasti(mech, ds, "has left %s's bay.");
	mech_notify(ds, MECHALL, tprintf("%s has left the bay.",
									 GetMechID(mech)));
	ContinueFlying(mech);
	if(In_Character(mech->mynum) && Location(MechPilot(mech)) != mech->mynum) {
		mech_notify(mech, MECHALL,
					"%ch%cr%cf%ciINTRUDER ALERT! INTRUDER ALERT!%c");
		mech_notify(mech, MECHALL,
					"%ch%cr%cfAutomatic self-destruct sequence initiated.%c");
		mech_shutdown(GOD, (void *) mech, "");
	}
	return 1;
}
Beispiel #5
0
void addMechToC3iNetwork(MECH * mech, MECH * mechToAdd)
{
    MECH *otherMech;
    MECH *otherNotifyMech;
    dbref otherRef;
    int i;
    int wPos = -1;

    debugC3(tprintf("ADD: %d to the C3i network of %d", mechToAdd->mynum,
	    mech->mynum));

    /* Find a position to add the new mech into my network */
    wPos = getFreeC3iNetworkPos(mech, mechToAdd);

    /* If we have a number that's less than 0, then we have an invalid position. Either we're already in the network or there's not enough room */
    if (wPos < 0)
	return;

    /* Well, we have a valid position, so let's put this mech in the network */
    MechC3iNetworkElem(mech, wPos) = mechToAdd->mynum;
    MechC3iNetworkSize(mech) += 1;

    mech_notify(mech, MECHALL,
	tprintf("%s connects to your C3i network.",
	    GetMechToMechID(mech, mechToAdd)));

    /* Now let's replicate the new network across the system so that everyone has the same network settings */
    for (i = 0; i < C3I_NETWORK_SIZE; i++) {
	otherRef = MechC3iNetworkElem(mech, i);

	otherMech = getOtherMechInNetwork(mech, i, 0, 0, 0, 0);

	if (!otherMech)
	    continue;

	if (!Good_obj(otherMech->mynum))
	    continue;

	if (otherRef != mechToAdd->mynum) {
	    otherNotifyMech = getOtherMechInNetwork(mech, i, 1, 1, 1, 0);

	    if (otherNotifyMech)
		mech_notify(otherNotifyMech, MECHALL,
		    tprintf("%s connects to your C3i network.",
			GetMechToMechID(otherNotifyMech, mechToAdd)));
	}

	replicateC3iNetwork(mech, otherMech);
    }

    /* Last, but not least, one final validation of the network */
    validateC3iNetwork(mech);
}
Beispiel #6
0
void mech_standfail_event(EVENT * e)
{
    MECH *mech = (MECH *) e->data;

    mech_notify(mech, MECHALL,
	"%cgYou have finally recovered from your attempt to stand.%c");
}
Beispiel #7
0
/* Basically the update events + some movenement events */
void mech_stabilizing_event(EVENT * e)
{
    MECH *mech = (MECH *) e->data;

    mech_notify(mech, MECHSTARTED,
	"%cgYou have finally stabilized after your jump.%c");
}
Beispiel #8
0
void CheckWeaponFailed(MECH * mech, int weapnum, int weaptype, int section,
					   int critical, int *modifier, int *type)
{
	short roll;
	int l = GetPartBrand(mech, section, critical);
	int t = GetPartType(mech, section, critical);
	int i = GetBrandIndex(t), in;

	*type = FAIL_NONE;
	if(i < 0)
		return;
	if(mudconf.btech_parts) {
		if(!l)
			l = 5;
		if(MechWeapons[Weapon2I(t)].special & PCOMBAT)
			return;
	} else
		return;
	if(Number(1, 10) < 9)
		return;
	if(Number(1, 100) <= brands[(i + l - 1) * 5 / 6].success)
		return;
	roll = Number(1, 6);
	if(roll == 6)
		roll = Number(1, 6);
	in = i + roll - 1;
	if(failures[in].flag & REQ_HEAT)
		if(!MechWeapons[weaptype].heat)
			return;
	if(failures[in].message && strcmp(failures[in].message, "none"))
		mech_notify(mech, MECHALL, failures[in].message);
	failures[in].func(mech, weapnum, weaptype, section, critical, roll,
					  modifier, type);
}
Beispiel #9
0
static void DS_Place(MECH * ds, MECH * mech, int frombay)
{
	int i;
	int nx, ny;
	MAP *mech_map;

	for(i = 0; i < NUM_BAYS; i++)
		if(AeroBay(ds, i) == frombay)
			break;
	if(i == NUM_BAYS || !(mech_map = getMap(mech->mapindex))) {
		/* i _should_ be set, otherwise things are deeply disturbing */
		mech_notify(mech, MECHALL, "Reality collapse imminent.");
		return;
	}
	i = Find_DS_Bay_Dir(ds, i);
	nx = dirs[(DSBearMod(ds) + i) % 6][0] + MechX(ds);
	ny = dirs[(DSBearMod(ds) + i) % 6][1] + MechY(ds) + KLUDGE(MechX(ds), nx);
	nx = BOUNDED(0, nx, mech_map->map_width - 1);
	ny = BOUNDED(0, ny, mech_map->map_height - 1);

	/* snippage from mech_Rsetxy */
	MechX(mech) = nx;
	MechLastX(mech) = nx;
	MechY(mech) = ny;
	MechLastY(mech) = ny;
	MechZ(mech) = MechZ(ds);
	MechElev(mech) = MechElev(ds);
	MapCoordToRealCoord(MechX(mech), MechY(mech), &MechFX(mech),
						&MechFY(mech));
	MechTerrain(mech) = GetTerrain(mech_map, MechX(mech), MechY(mech));
}
Beispiel #10
0
void mech_fall_event(EVENT * e)
{
    MECH *mech = (MECH *) e->data;
    int fallspeed = (int) e->data2;
    int fallen_elev;

    if (Started(mech) && fallspeed >= 0)
	return;
    if (fallspeed <= 0 && (!Started(mech) || !(FlyingT(mech)) ||
	    ((AeroFuel(mech) <= 0) && !AeroFreeFuel(mech)) ||
	    ((MechType(mech) == CLASS_VTOL) &&
		(SectIsDestroyed(mech, ROTOR)))))
	fallspeed -= FALL_ACCEL;
    else
	fallspeed += FALL_ACCEL;
    MarkForLOSUpdate(mech);
    if (MechsElevation(mech) > abs(fallspeed)) {
	MechZ(mech) -= abs(fallspeed);
	MechFZ(mech) = MechZ(mech) * ZSCALE;
	MECHEVENT(mech, EVENT_FALL, mech_fall_event, FALL_TICK, fallspeed);
	return;
    }
    /* Time to hit da ground */
    fallen_elev = factoral(abs(fallspeed));
    mech_notify(mech, MECHALL, "You hit the ground!");
    MechLOSBroadcast(mech, "hits the ground!");
    MechFalls(mech, fallen_elev, 0);
    MechStatus(mech) &= ~JUMPING;
}
Beispiel #11
0
void mech_stand_event(EVENT * e)
{
    MECH *mech = (MECH *) e->data;

    MechLOSBroadcast(mech, "stands up!");
    mech_notify(mech, MECHALL, "You have finally finished standing up.");
    MakeMechStand(mech);
}
Beispiel #12
0
static void mech_rrec_event(MUXEVENT * e)
{
	MECH *mech = (MECH *) e->data;
	int val = (int) e->data2;

	MechRadioRange(mech) += val;
	if(!Destroyed(mech) && val == MechRadioRange(mech))
		mech_notify(mech, MECHALL, "Your radio is now operational again.");
}
Beispiel #13
0
void unstun_crew_event(EVENT * e)
{
    MECH *mech = (MECH *) e->data;

    if (CrewStunned(mech) > 1)	/* If we've been stunned again! */
	return;

    mech_notify(mech, MECHALL,
	"Your head clears and you're able to control your vehicle again.");
    MechTankCritStatus(mech) &= ~CREW_STUNNED;
}
Beispiel #14
0
void CheckGenericFail(MECH * mech, int type, int *result, int *mod)
{
	int i = GetBrandIndex(type);
	int l = type == -1 ? MechComputer(mech) : MechRadio(mech);
	int roll, in;

	if(result)
		*result = FAIL_NONE;
	if(i < 0)
		return;
	if(mudconf.btech_parts) {
		if(!l)
			l = 5;
	} else
		return;
	if(Number(1, 5000) != 42)
		return;					/* ~1/5000 chance */
	if(Number(1, 100) <= brands[(i + l - 1) * 5 / 6].success)
		return;
	roll = Number(1, 6);
	if(roll == 6)
		roll = Number(1, 6);
	in = i + roll - 1;
	switch (failures[in].flag) {
	case REQ_TARGET:
		if(MechTarget(mech) <= 0)
			return;
		break;
	case REQ_TAC:
		if(MechTacRange(mech) == 0)
			return;
		break;
	case REQ_LRS:
		if(MechLRSRange(mech) == 0)
			return;
		break;
	case REQ_SCANNERS:
		if(MechTacRange(mech) == 0 || MechLRSRange(mech) == 0 ||
		   MechScanRange(mech) == 0)
			return;
		break;
	case REQ_COMPUTER:
		/* */
		break;
	case REQ_RADIO:
		if(MechRadioRange(mech) == 0)
			return;
		break;
	}
	if(failures[in].message && strcmp(failures[in].message, "none"))
		mech_notify(mech, MECHALL, failures[in].message);
	failures[in].func(mech, -1, -1, -1, -1, roll, mod, result);
}
Beispiel #15
0
void mech_lateral_event(EVENT * e)
{
    MECH *mech = (MECH *) e->data;
    int latmode = (int) e->data2;

    if (!mech || !Started(mech))
	return;
    mech_notify(mech, MECHALL,
	tprintf("Lateral movement mode change to %s completed.",
	    lateral_modes[latmode].full));
    MechLateral(mech) = lateral_modes[latmode].ofs;
}
Beispiel #16
0
void mech_recovery_event(EVENT * e)
{
    MECH *mech = (MECH *) e->data;

    if (Destroyed(mech) || !Uncon(mech))
	return;
    if (handlemwconc(mech, 0)) {
	MechStatus(mech) &= ~UNCONSCIOUS;
	mech_notify(mech, MECHALL, "The pilot regains consciousness!");
	return;
    }
}
Beispiel #17
0
/* This is just a 'toy' event */
void mech_lock_event(EVENT * e)
{
    MECH *mech = (MECH *) e->data;
    MAP *map;
    MECH *target;

    if (MechTarget(mech) >= 0) {
	map = getMap(mech->mapindex);
	target = FindObjectsData(MechTarget(mech));
	if (!target)
	    return;
	if (!InLineOfSight(mech, target, MechX(target), MechY(target),
		FlMechRange(map, mech, target)))
	    return;
	mech_notify(mech, MECHALL,
	    tprintf("The sensors acquire a stable lock on %s.",
		GetMechToMechID(mech, target)));
    } else if (MechTargX(mech) >= 0 && MechTargY(mech) >= 0)
	mech_notify(mech, MECHALL,
	    tprintf("The sensors acquire a stable lock on (%d,%d).",
		MechTargX(mech), MechTargY(mech)));

}
Beispiel #18
0
static void mech_enterbay_event(MUXEVENT * e)
{
	MECH *mech = (MECH *) e->data, *ds, *tmpm = NULL;
	long ref = (long) e->data2;
	long bayn;
	int x = 5, y = 5;
	MAP *tmpmap;

	if(!Started(mech) || Uncon(mech) || Jumping(mech) ||
	   (MechType(mech) == CLASS_MECH && (Fallen(mech) || Standing(mech))) ||
	   OODing(mech) || (fabs(MechSpeed(mech)) * 5 >= MMaxSpeed(mech) &&
						fabs(MMaxSpeed(mech)) >= MP1)
	   || (MechType(mech) == CLASS_VTOL && AeroFuel(mech) <= 0))
		return;
	tmpmap = getMap(ref);
	if(!(ds = getMech(tmpmap->onmap)))
		return;
	if(!Find_DS_Bay_In_MechHex(mech, ds, &bayn))
		return;
	/* whee */
	ref = AeroBay(ds, bayn);
	StopBSuitSwarmers(FindObjectsData(mech->mapindex), mech, 1);
	mech_notify(mech, MECHALL, "You enter the bay.");
	MechLOSBroadcast(mech, tprintf("has entered %s at %d,%d.",
								   GetMechID(ds), MechX(mech), MechY(mech)));
	MarkForLOSUpdate(mech);
	if(MechType(mech) == CLASS_MW && !In_Character(ref)) {
		enter_mw_bay(mech, ref);
		return;
	}
	if(MechCarrying(mech) > 0)
		tmpm = getMech(MechCarrying(mech));
	mech_Rsetmapindex(GOD, (void *) mech, tprintf("%d", ref));
	mech_Rsetxy(GOD, (void *) mech, tprintf("%d %d", x, y));
	MechLOSBroadcast(mech, "has entered the bay.");
	loud_teleport(mech->mynum, ref);
	if(tmpm) {
		mech_Rsetmapindex(GOD, (void *) tmpm, tprintf("%d", ref));
		mech_Rsetxy(GOD, (void *) tmpm, tprintf("%d %d", x, y));
		loud_teleport(tmpm->mynum, ref);
	}
}
Beispiel #19
0
void sendECMNotification(MECH * objMech, int wMsgType)
{
	switch (wMsgType) {
	case ECM_NOTIFY_DISTURBED:

#ifdef LOUD_ECM
		mech_notify(objMech, MECHALL,
					"Half your screens are suddenly filled with static!");

#ifdef VERY_LOUD_ECM
		if(MechSpecials(objMech) & BEAGLE_PROBE_TECH &&
		   !(MechCritStatus(objMech) & BEAGLE_DESTROYED))
			mech_notify(objMech, MECHALL,
						"Your Beagle Active Probe is inoperative!");
		if(MechSpecials2(objMech) & BLOODHOUND_PROBE_TECH &&
		   !(MechCritStatus(objMech) & BLOODHOUND_DESTROYED))
			mech_notify(objMech, MECHALL,
						"Your Bloodhound Active Probe is inoperative!");
		if(MechSpecials(objMech) & LIGHT_BAP_TECH &&
		   !(MechCritStatus2(objMech) & LIGHT_BAP_DESTROYED))
		   	mech_notify(objMech, MECHALL,
						"Your Light Beagle Active Probe is inoperative!");
		if(IsC3(objMech))
			mech_notify(objMech, MECHALL, "Your C3 network is inoperative!");
		if(IsC3i(objMech))
			mech_notify(objMech, MECHALL, "Your C3i network is inoperative!");

#endif /*  */
#endif /*  */
		break;
	case ECM_NOTIFY_UNDISTURBED:

#ifdef LOUD_ECM
		mech_notify(objMech, MECHALL,
					"All your systems are back to normal again!");

#ifdef VERY_LOUD_ECM
		if(MechSpecials(objMech) & BEAGLE_PROBE_TECH &&
		   !(MechCritStatus(objMech) & BEAGLE_DESTROYED))
			mech_notify(objMech, MECHALL,
						"Your Beagle Active Probe is operational again!");
		if(MechSpecials2(objMech) & BLOODHOUND_PROBE_TECH &&
		   !(MechCritStatus(objMech) & BLOODHOUND_DESTROYED))
			mech_notify(objMech, MECHALL,
						"Your Bloodhound Active Probe is operational again!");
		if(MechSpecials(objMech) & LIGHT_BAP_TECH &&
		   !(MechCritStatus2(objMech) & LIGHT_BAP_DESTROYED))
		   	mech_notify(objMech, MECHALL,
						"Your Light Beagle Active Probe is operational again!");
		if(IsC3(objMech))
			mech_notify(objMech, MECHALL,
						"Your C3 network is operational again!");
		if(IsC3i(objMech))
			mech_notify(objMech, MECHALL,
						"Your C3i network is operational again!");

#endif /*  */
#endif /*  */
		break;
	case ECM_NOTIFY_COUNTERED:
		if(HasWorkingECMSuite(objMech))
			mech_notify(objMech, MECHALL,
						"Your ECM suite's ready light turns red, countered by enemy ECCM!");
		break;
	case ECM_NOTIFY_UNCOUNTERED:
		if(HasWorkingECMSuite(objMech))
			mech_notify(objMech, MECHALL,
						"Your ECM suite's ready light turns green, enemy ECCM is out of range.");
		break;
	}
}
Beispiel #20
0
void mech_c3i_join_leave(dbref player, void *data, char *buffer)
{
    MECH *mech = (MECH *) data, *target;
    MAP *objMap;
    char *args[2];
    dbref refTarget;
    int LOS = 1;
    float range = 0.0;

    cch(MECH_USUALO);

    DOCHECK(mech_parseattributes(buffer, args, 2) != 1,
	"Invalid number of arguments to function!");

    DOCHECK(!HasC3i(mech), "This unit is not equipped with C3i!");
    DOCHECK(C3iDestroyed(mech), "Your C3i system is destroyed!");
    DOCHECK(AnyECMDisturbed(mech),
	"Your C3i system is not currently operational!");

    validateC3iNetwork(mech);

    /* Clear our C3i Network */
    if (!strcmp(args[0], "-")) {
	if (MechC3iNetworkSize(mech) <= 0) {
	    mech_notify(mech, MECHALL,
		"You are not connected to a C3i network!");

	    return;
	}

	clearC3iNetwork(mech, 1);

	mech_notify(mech, MECHALL, "You disconnect from the C3i network.");

	return;
    }

    /* Well, if we're here then we wanna connect to a network */
    /* Let's check to see if we're already in one... can't be in two at the same time */
    DOCHECK(MechC3iNetworkSize(mech) > 0,
	"You are already in a C3i network!");

    objMap = getMap(mech->mapindex);

    /* Find who we're trying to connect to */
    refTarget = FindTargetDBREFFromMapNumber(mech, args[0]);
    target = getMech(refTarget);

    if (target) {
	LOS =
	    InLineOfSight(mech, target, MechX(target), MechY(target),
	    range);
    } else
	refTarget = 0;

    DOCHECK((refTarget < 1) ||
	!LOS, "That is not a valid targetID. Try again.");
    DOCHECK(MechTeam(mech) != MechTeam(target),
	"You can't use the C3i network of unfriendly units!");
    DOCHECK(mech == target, "You can't connect to yourself!");
    DOCHECK(Destroyed(target), "That unit is destroyed!");
    DOCHECK(!Started(target), "That unit is not started!");
    DOCHECK(!HasC3i(target),
	"That unit does not appear to be equipped with C3i!");

    /* validate the network of our target */
    validateC3iNetwork(target);
    DOCHECK(MechC3iNetworkSize(target) >= C3I_NETWORK_SIZE,
	"That unit's C3i network is operating at maximum capacity!");

    /* Connect us up */
    mech_notify(mech, MECHALL, tprintf("You connect to %s's C3i network.",
	    GetMechToMechID(mech, target)));

    addMechToC3iNetwork(target, mech);
}
Beispiel #21
0
void mech_unjam_ammo_event(EVENT * objEvent)
{
    MECH *objMech = (MECH *) objEvent->data;	/* get the mech */
    int wWeapNum = (int) objEvent->data2;	/* and now the weapon number */
    int wSect, wSlot, wWeapStatus, wWeapIdx;
    int ammoLoc, ammoCrit, ammoLeft;
    int wRoll = 0;
    int wRollNeeded = 0;

    if (Uncon(objMech) || !Started(objMech))
	return;

    wWeapStatus =
	FindWeaponNumberOnMech(objMech, wWeapNum, &wSect, &wSlot);

    if (wWeapStatus == TIC_NUM_DESTROYED)	/* return if the weapon has been destroyed */
	return;

    wWeapIdx = FindWeaponIndex(objMech, wWeapNum);
    ammoLeft =
	FindAmmoForWeapon_sub(objMech, wSect, wSlot, wWeapIdx, 0, &ammoLoc,
	&ammoCrit, 0, 0);

    if (!ammoLeft) {
	SetPartTempNuke(objMech, wSect, wSlot, 0);

	mech_notify(objMech, MECHALL,
	    tprintf
	    ("You finish bouncing around and realize you nolonger have ammo for your %s!",
		get_parts_long_name(I2Weapon(wWeapIdx), 0)));
	return;
    }

    if (MechWeapons[wWeapStatus].special & RAC) {
	wRoll = Roll();
	wRollNeeded = FindPilotGunnery(objMech, wWeapStatus) + 3;

	mech_notify(objMech, MECHPILOT,
	    "You make a roll to unjam the weapon!");
	mech_notify(objMech, MECHPILOT,
	    tprintf("Modified Gunnery Skill: BTH %d\tRoll: %d",
		wRollNeeded, wRoll));

	if (wRoll < wRollNeeded) {
	    mech_notify(objMech, MECHALL,
		"Your attempt to remove the jammed slug fails. You'll need to try again to clear it.");
	    return;
	}
    } else {
	if (!MadePilotSkillRoll(objMech, 0)) {
	    mech_notify(objMech, MECHALL,
		"Your attempt to remove the jammed slug fails. You'll need to try again to clear it.");
	    return;
	}
    }

    SetPartTempNuke(objMech, wSect, wSlot, 0);
    mech_notify(objMech, MECHALL,
	tprintf("You manage to clear the jam on your %s!",
	    get_parts_long_name(I2Weapon(wWeapIdx), 0)));
    MechLOSBroadcast(objMech, "ejects a mangled shell!");

    SetPartData(objMech, ammoLoc, ammoCrit, GetPartData(objMech, ammoLoc,
	    ammoCrit) - 1);
}