Skip to content

Commit

Permalink
Merge pull request #6209 from MegaMek/laser-pulse-module
Browse files Browse the repository at this point in the history
Implement RISC laser pulse module
  • Loading branch information
HammerGS authored Nov 23, 2024
2 parents 518b8ab + 5e1928b commit 2590e1e
Show file tree
Hide file tree
Showing 18 changed files with 119 additions and 56 deletions.
1 change: 1 addition & 0 deletions megamek/i18n/megamek/common/equipmentmessages.properties
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ EquipmentMode.Off=Off
EquipmentMode.Armed=Armed
EquipmentMode.Normal=Normal
EquipmentMode.Aimed\ shot=Aimed shot
EquipmentMode.Pulse=Pulse

EquipmentMode.Bracket\ 80%=Bracket 80%
EquipmentMode.Bracket\ 60%=Bracket 60%
Expand Down
6 changes: 3 additions & 3 deletions megamek/src/megamek/client/bot/princess/FireControl.java
Original file line number Diff line number Diff line change
Expand Up @@ -902,8 +902,8 @@ ToHitData guessToHitModifierForWeapon(final Entity shooter,
toHit.append(getDamageWeaponMods(shooter, weapon));

// weapon mods
if (0 != weaponType.getToHitModifier()) {
toHit.addModifier(weaponType.getToHitModifier(), TH_WEAPON_MOD);
if (0 != weaponType.getToHitModifier(weapon)) {
toHit.addModifier(weaponType.getToHitModifier(weapon), TH_WEAPON_MOD);
}

// Target size.
Expand Down Expand Up @@ -3475,7 +3475,7 @@ AmmoMounted getAntiAirAmmo(final List<AmmoMounted> ammoList,
if (!(weaponType instanceof MMLWeapon)) {
// Naively assume that easier-hitting is better
if (returnAmmo != null) {
AmmoType returnAmmoType = (AmmoType) (returnAmmo.getType());
AmmoType returnAmmoType = returnAmmo.getType();
returnAmmo = ((ammoType.getToHitModifier() > returnAmmoType.getToHitModifier()) ? ammo
: returnAmmo);
} else {
Expand Down
2 changes: 1 addition & 1 deletion megamek/src/megamek/client/ui/swing/EquipChoicePanel.java
Original file line number Diff line number Diff line change
Expand Up @@ -1139,7 +1139,7 @@ public void applyChoice() {
if (chHotLoad.isSelected() != m_mounted.isHotLoaded()) {
m_mounted.setHotLoad(chHotLoad.isSelected());
// Set the mode too, so vehicles can switch back
int numModes = m_mounted.getType().getModesCount();
int numModes = m_mounted.getModesCount();
for (int m = 0; m < numModes; m++) {
if (m_mounted.getType().getMode(m).getName()
.equals("HotLoad")) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -225,13 +225,18 @@ public WeaponMounted getWeaponAt(int index) {
@Override
public String getElementAt(int index) {
final WeaponMounted mounted = weapons.get(index);
final WeaponType wtype = (WeaponType) mounted.getType();
final WeaponType wtype = mounted.getType();
Game game = null;
if (unitDisplay.getClientGUI() != null) {
game = unitDisplay.getClientGUI().getClient().getGame();
}

StringBuilder wn = new StringBuilder(mounted.getDesc());
if ((mounted.getLinkedBy() != null)
&& (mounted.getLinkedBy().getType() instanceof MiscType)
&& (mounted.getLinkedBy().getType().hasFlag(MiscType.F_RISC_LASER_PULSE_MODULE))) {
wn.append("+").append(mounted.getLinkedBy().getShortName());
}
wn.append(" [");
wn.append(en.getLocationAbbr(mounted.getLocation()));
//Check if mixedTech and add Clan or IS tag
Expand Down
4 changes: 4 additions & 0 deletions megamek/src/megamek/common/AmmoType.java
Original file line number Diff line number Diff line change
Expand Up @@ -484,6 +484,10 @@ public int getAmmoType() {
return ammoType;
}

public int getToHitModifier() {
return toHitModifier;
}

/**
* Analog to WeaponType.getFireTNRoll(), but based on munitions.
* See TO:AR pg 42
Expand Down
1 change: 1 addition & 0 deletions megamek/src/megamek/common/Compute.java
Original file line number Diff line number Diff line change
Expand Up @@ -7248,6 +7248,7 @@ public static boolean allowAimedShotWith(WeaponMounted weapon, AimingMode aiming
case TARGETING_COMPUTER:
if (!wtype.hasFlag(WeaponType.F_DIRECT_FIRE)
|| wtype.hasFlag(WeaponType.F_PULSE)
|| weapon.curMode().getName().equals("Pulse")
|| (wtype instanceof HAGWeapon)) {
return false;
}
Expand Down
11 changes: 10 additions & 1 deletion megamek/src/megamek/common/EquipmentType.java
Original file line number Diff line number Diff line change
Expand Up @@ -502,7 +502,7 @@ public boolean isSpreadable() {
return spreadable;
}

public int getToHitModifier() {
public int getToHitModifier(@Nullable Mounted<?> mounted) {
return toHitModifier;
}

Expand Down Expand Up @@ -555,6 +555,15 @@ public boolean hasModeType(String modeType) {
return false;
}

/**
* @param mounted The equipment mount. In some cases the moudes are affected by linked equipment.
* @return the number of modes that this type of equipment can be in or
* <code>0</code> if it doesn't have modes.
*/
public int getModesCount(Mounted<?> mounted) {
return getModesCount();
}

/**
* @return the number of modes that this type of equipment can be in or
* <code>0</code> if it doesn't have modes.
Expand Down
21 changes: 10 additions & 11 deletions megamek/src/megamek/common/MiscType.java
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@
import java.math.BigInteger;
import java.text.NumberFormat;

import megamek.common.equipment.MiscMounted;
import megamek.common.equipment.WeaponMounted;
import megamek.common.miscGear.AntiMekGear;
import megamek.common.weapons.ppc.CLERPPC;
import megamek.common.weapons.ppc.ISERPPC;
Expand Down Expand Up @@ -962,10 +964,9 @@ public double getCost(Entity entity, boolean isArmored, int loc, double size) {
}
}

for (Mounted<?> mo : entity.getMisc()) {
MiscType mt = (MiscType) mo.getType();
if (mt.hasFlag(MiscType.F_RISC_LASER_PULSE_MODULE)) {
fTons += mo.getTonnage();
for (MiscMounted mounted : entity.getMisc()) {
if (mounted.getType().hasFlag(MiscType.F_RISC_LASER_PULSE_MODULE)) {
fTons += mounted.getTonnage();
}
}
if (getInternalName().equals("ISTargeting Computer")) {
Expand Down Expand Up @@ -1110,17 +1111,15 @@ public int getCriticals(Entity entity, double size) {
} else if (hasFlag(F_TARGCOMP)) {
// based on tonnage of direct_fire weaponry
double fTons = 0.0;
for (Mounted<?> m : entity.getWeaponList()) {
WeaponType wt = (WeaponType) m.getType();
if (wt.hasFlag(WeaponType.F_DIRECT_FIRE)) {
for (WeaponMounted m : entity.getWeaponList()) {
if (m.getType().hasFlag(WeaponType.F_DIRECT_FIRE)) {
fTons += m.getTonnage();
}
}

for (Mounted<?> mo : entity.getMisc()) {
MiscType mt = (MiscType) mo.getType();
if (mt.hasFlag(MiscType.F_RISC_LASER_PULSE_MODULE)) {
fTons += mo.getTonnage();
for (MiscMounted mounted : entity.getMisc()) {
if (mounted.getType().hasFlag(MiscType.F_RISC_LASER_PULSE_MODULE)) {
fTons += mounted.getTonnage();
}
}
if (TechConstants.isClan(getTechLevel(entity.getTechLevelYear()))) {
Expand Down
2 changes: 1 addition & 1 deletion megamek/src/megamek/common/Mounted.java
Original file line number Diff line number Diff line change
Expand Up @@ -229,7 +229,7 @@ protected void setType(T type) {
}

public int getModesCount() {
return getType().getModesCount();
return getType().getModesCount(this);
}

protected EquipmentMode getMode(int mode) {
Expand Down
4 changes: 2 additions & 2 deletions megamek/src/megamek/common/WeaponType.java
Original file line number Diff line number Diff line change
Expand Up @@ -805,8 +805,8 @@ && getLongRange() < AlphaStrikeElement.LONG_RANGE) {
damage = adjustBattleForceDamageForMinRange(damage);
}

if (getToHitModifier() != 0) {
damage -= damage * getToHitModifier() * 0.05;
if (getToHitModifier(null) != 0) {
damage -= damage * getToHitModifier(null) * 0.05;
}
}

Expand Down
8 changes: 4 additions & 4 deletions megamek/src/megamek/common/actions/WeaponAttackAction.java
Original file line number Diff line number Diff line change
Expand Up @@ -3193,8 +3193,8 @@ private static ToHitData compileWeaponToHitMods(Game game, Entity ae, Entity spo
}

// Flat to hit modifiers defined in WeaponType
if (wtype.getToHitModifier() != 0) {
int modifier = wtype.getToHitModifier();
if (wtype.getToHitModifier(weapon) != 0) {
int modifier = wtype.getToHitModifier(weapon);
if (wtype instanceof VariableSpeedPulseLaserWeapon) {
int nRange = ae.getPosition().distance(target.getPosition());
int[] nRanges = wtype.getRanges(weapon, ammo);
Expand Down Expand Up @@ -5243,8 +5243,8 @@ private static ToHitData artilleryDirectToHit(Game game, Entity ae, Targetable t
toHit.addModifier(ae.getHeatFiringModifier(), Messages.getString("WeaponAttackAction.Heat"));
}
// weapon to-hit modifier
if (wtype.getToHitModifier() != 0) {
toHit.addModifier(wtype.getToHitModifier(), Messages.getString("WeaponAttackAction.WeaponMod"));
if (wtype.getToHitModifier(weapon) != 0) {
toHit.addModifier(wtype.getToHitModifier(weapon), Messages.getString("WeaponAttackAction.WeaponMod"));
}
// ammo to-hit modifier
if (usesAmmo && (atype.getToHitModifier() != 0)) {
Expand Down
3 changes: 3 additions & 0 deletions megamek/src/megamek/common/equipment/WeaponMounted.java
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,9 @@ && getLinkedBy().getType().hasFlag(
heat++;
}
}
if (curMode().equals("Pulse")) {
heat += 2;
}

return heat;
}
Expand Down
15 changes: 7 additions & 8 deletions megamek/src/megamek/common/verifier/TestEntity.java
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
import megamek.common.annotations.Nullable;
import megamek.common.enums.MPBoosters;
import megamek.common.equipment.ArmorType;
import megamek.common.equipment.MiscMounted;
import megamek.common.equipment.WeaponMounted;
import megamek.common.util.StringUtil;
import megamek.common.weapons.battlearmor.BAFlamerWeapon;
Expand Down Expand Up @@ -788,16 +789,14 @@ public int calcMiscCrits(MiscType mt, double size) {
}
} else if (mt.hasFlag(MiscType.F_TARGCOMP)) {
double fTons = 0.0f;
for (Mounted<?> mo : getEntity().getWeaponList()) {
WeaponType wt = (WeaponType) mo.getType();
if (wt.hasFlag(WeaponType.F_DIRECT_FIRE)) {
fTons += mo.getTonnage();
for (WeaponMounted mounted : getEntity().getWeaponList()) {
if (mounted.getType().hasFlag(WeaponType.F_DIRECT_FIRE)) {
fTons += mounted.getTonnage();
}
}
for (Mounted<?> mo : getEntity().getMisc()) {
MiscType mt2 = (MiscType) mo.getType();
if (mt2.hasFlag(MiscType.F_RISC_LASER_PULSE_MODULE)) {
fTons += mo.getTonnage();
for (MiscMounted mounted : getEntity().getMisc()) {
if (mounted.getType().hasFlag(MiscType.F_RISC_LASER_PULSE_MODULE)) {
fTons += mounted.getTonnage();
}
}
double weight = 0.0f;
Expand Down
28 changes: 20 additions & 8 deletions megamek/src/megamek/common/weapons/PulseLaserWeaponHandler.java
Original file line number Diff line number Diff line change
Expand Up @@ -19,23 +19,35 @@
*/
package megamek.common.weapons;

import megamek.common.BattleArmor;
import megamek.common.Compute;
import megamek.common.Game;
import megamek.common.Infantry;
import megamek.common.RangeType;
import megamek.common.ToHitData;
import megamek.common.*;
import megamek.common.actions.WeaponAttackAction;
import megamek.common.equipment.WeaponMounted;
import megamek.common.options.OptionsConstants;
import megamek.server.totalwarfare.TWGameManager;

import java.util.Vector;

public class PulseLaserWeaponHandler extends EnergyWeaponHandler {
private static final long serialVersionUID = -5701939682138221449L;

public PulseLaserWeaponHandler(ToHitData toHit, WeaponAttackAction waa, Game g, TWGameManager m) {
super(toHit, waa, g, m);
}

@Override
protected boolean doChecks(Vector<Report> vPhaseReport) {
if (super.doChecks(vPhaseReport)) {
return true;
}

WeaponMounted laser = waa.getEntity(game).getWeapon(waa.getWeaponId());

if ((roll.getIntValue() == 2) && laser.curMode().equals("Pulse")) {
vPhaseReport.addAll(gameManager.explodeEquipment(laser.getEntity(), laser.getLocation(), laser.getLinkedBy()));
}
return false;
}

@Override
protected int calcDamagePerHit() {
double toReturn = wtype.getDamage();
Expand Down Expand Up @@ -70,7 +82,7 @@ protected int calcDamagePerHit() {
if (game.getOptions().booleanOption(OptionsConstants.ADVCOMBAT_TACOPS_LOS_RANGE)
&& (nRange > wtype.getRanges(weapon)[RangeType.RANGE_EXTREME])) {
toReturn = (int) Math.floor(toReturn / 3.0);
}
}

if (target.isConventionalInfantry()) {
toReturn = Compute.directBlowInfantryDamage(toReturn,
Expand All @@ -81,7 +93,7 @@ protected int calcDamagePerHit() {
} else if (bDirect) {
toReturn = Math.min(toReturn + (toHit.getMoS() / 3), toReturn * 2);
}

toReturn = applyGlancingBlowModifier(toReturn, target.isConventionalInfantry());
return (int) Math.ceil(toReturn);
}
Expand Down
52 changes: 41 additions & 11 deletions megamek/src/megamek/common/weapons/lasers/LaserWeapon.java
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,14 @@
import megamek.common.Mounted;
import megamek.common.ToHitData;
import megamek.common.actions.WeaponAttackAction;
import megamek.common.annotations.Nullable;
import megamek.common.equipment.MiscMounted;
import megamek.common.options.GameOptions;
import megamek.common.options.OptionsConstants;
import megamek.common.weapons.AttackHandler;
import megamek.common.weapons.EnergyWeaponHandler;
import megamek.common.weapons.InsulatedLaserWeaponHandler;
import megamek.common.weapons.PulseLaserWeaponHandler;
import megamek.server.totalwarfare.TWGameManager;

/**
Expand All @@ -39,21 +44,46 @@ public LaserWeapon() {
atClass = CLASS_LASER;
}

/*
* (non-Javadoc)
*
* @see
* megamek.common.weapons.Weapon#getCorrectHandler(megamek.common.ToHitData,
* megamek.common.actions.WeaponAttackAction, megamek.common.Game,
* megamek.server.Server)
*/
@Override
public void adaptToGameOptions(GameOptions gOp) {
super.adaptToGameOptions(gOp);

if (!(this instanceof PulseLaserWeapon)) {
addMode("");
addMode("Pulse");
}
}

@Override
public int getModesCount(Mounted<?> mounted) {
Mounted<?> linkedBy = mounted.getLinkedBy();
if ((linkedBy instanceof MiscMounted)
&& !linkedBy.isInoperable()
&& ((MiscMounted) linkedBy).getType().hasFlag(MiscType.F_RISC_LASER_PULSE_MODULE)) {
return 2;
} else {
return 0;
}
}

@Override
public int getToHitModifier(@Nullable Mounted<?> mounted) {
if ((mounted == null) || !(mounted.getLinkedBy() instanceof MiscMounted) || !mounted.getLinkedBy().getType().hasFlag(MiscType.F_RISC_LASER_PULSE_MODULE)) {
return super.getToHitModifier(mounted);
}
return mounted.curMode().getName().equals("Pulse") ? -2 : 0;
}

@Override
protected AttackHandler getCorrectHandler(ToHitData toHit, WeaponAttackAction waa, Game game,
TWGameManager manager) {
Mounted<?> linkedBy = waa.getEntity(game).getEquipment(waa.getWeaponId()).getLinkedBy();
if ((linkedBy != null) && !linkedBy.isInoperable()
&& linkedBy.getType().hasFlag(MiscType.F_LASER_INSULATOR)) {
return new InsulatedLaserWeaponHandler(toHit, waa, game, manager);
if ((linkedBy != null) && !linkedBy.isInoperable()) {
if (linkedBy.getType().hasFlag(MiscType.F_LASER_INSULATOR)) {
return new InsulatedLaserWeaponHandler(toHit, waa, game, manager);
} else if (linkedBy.getType().hasFlag(MiscType.F_RISC_LASER_PULSE_MODULE)) {
return new PulseLaserWeaponHandler(toHit, waa, game, manager);
}
}
return new EnergyWeaponHandler(toHit, waa, game, manager);
}
Expand Down
4 changes: 2 additions & 2 deletions megamek/src/megamek/common/weapons/ppc/PPCWeapon.java
Original file line number Diff line number Diff line change
Expand Up @@ -73,8 +73,8 @@ public double getBattleForceDamage(int range, Mounted<?> capacitor) {
if ((range == AlphaStrikeElement.SHORT_RANGE) && (getMinimumRange() > 0)) {
damage = adjustBattleForceDamageForMinRange(damage);
}
if (getToHitModifier() != 0) {
damage -= damage * getToHitModifier() * 0.05;
if (getToHitModifier(null) != 0) {
damage -= damage * getToHitModifier(null) * 0.05;
}
}
return damage / 10.0;
Expand Down
2 changes: 1 addition & 1 deletion megamek/src/megamek/server/totalwarfare/TWGameManager.java
Original file line number Diff line number Diff line change
Expand Up @@ -24630,7 +24630,7 @@ public Vector<Report> explodeEquipment(Entity en, int loc, Mounted<?> mounted, b
// attached to
if ((mounted.getType() instanceof MiscType) && mounted.getType().hasFlag(MiscType.F_RISC_LASER_PULSE_MODULE)) {
hit.setEffect(HitData.EFFECT_NO_CRITICALS);
Mounted<?> laser = mounted.getLinkedBy();
Mounted<?> laser = mounted.getLinked();
if (en instanceof Mek) {
for (int slot = 0; slot < en.getNumberOfCriticals(laser.getLocation()); slot++) {
CriticalSlot cs = en.getCritical(laser.getLocation(), slot);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1862,13 +1862,13 @@ void testGuessToHitModifierForWeapon() {
when(((Mek) mockTarget).getCockpitType()).thenReturn(Mek.COCKPIT_STANDARD);

// Test weapon mods.
when(mockWeaponType.getToHitModifier()).thenReturn(-2);
when(mockWeaponType.getToHitModifier(mockWeapon)).thenReturn(-2);
expected = new ToHitData(mockShooter.getCrew().getGunnery(), FireControl.TH_GUNNERY);
expected.addModifier(FireControl.TH_MEDIUM_RANGE);
expected.addModifier(-2, FireControl.TH_WEAPON_MOD);
assertToHitDataEquals(expected, testFireControl.guessToHitModifierForWeapon(mockShooter,
mockShooterState, mockTarget, mockTargetState, mockWeapon, mockAmmo, mockGame));
when(mockWeaponType.getToHitModifier()).thenReturn(0);
when(mockWeaponType.getToHitModifier(mockWeapon)).thenReturn(0);

// Test heat mods.
when(mockShooter.getHeatFiringModifier()).thenReturn(1);
Expand Down

0 comments on commit 2590e1e

Please sign in to comment.