Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement RISC laser pulse module #6209

Merged
merged 10 commits into from
Nov 23, 2024
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) {
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There are some cases (particularly in AlphaStrike and BattleForce conversion code) where the Mounted is not available. In those cases a null is passed, which skips the check for the laser pulse module.

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 @@ -24381,7 +24381,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
Loading