Skip to content

Commit

Permalink
feat: add ground roles, cover, some more things in movement
Browse files Browse the repository at this point in the history
  • Loading branch information
Scoppio committed Jan 7, 2025
1 parent 6d664d5 commit 041f818
Show file tree
Hide file tree
Showing 20 changed files with 1,109 additions and 67 deletions.
1 change: 1 addition & 0 deletions megamek/i18n/megamek/common/messages.properties
Original file line number Diff line number Diff line change
Expand Up @@ -612,6 +612,7 @@ BombMessage.drifted=Bomb drifted here from
acar.invalid_attack=Invalid attack
acar.invalid_skill=Invalid skill
acar.skill=Skill
acar.cover=Partial Cover
acar.critical_target_damage=Critical Target Damage
acar.skill_7=Wet behind the ears (skill)
acar.skill_6=Really Green (skill)
Expand Down
14 changes: 12 additions & 2 deletions megamek/src/megamek/common/alphaStrike/ASRange.java
Original file line number Diff line number Diff line change
Expand Up @@ -21,14 +21,24 @@
public enum ASRange {
SHORT, MEDIUM, LONG, EXTREME, HORIZON;

public boolean insideRange(int distance) {
return switch (this) {
case SHORT -> distance <= 6;
case MEDIUM -> distance <= 24;
case LONG -> distance <= 42;
case EXTREME -> distance <= 60;
case HORIZON -> distance > 60;
};
}

public static ASRange fromDistance(int distance) {
if (distance <= 6) {
return SHORT;
} else if (distance <= 24) {
return MEDIUM;
} else if (distance < 42) {
} else if (distance <= 42) {
return LONG;
} else if (distance < 60) {
} else if (distance <= 60) {
return EXTREME;
} else {
return HORIZON;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,19 +34,27 @@ public static AttackToHitData compileToHit(SimulationContext game, StandardUnitA
}

var attackingFormation = game.getFormation(attack.getEntityId()).orElseThrow();
var unit = attackingFormation.getUnits().get(attack.getUnitNumber());
// var unit = attackingFormation.getUnits().get(attack.getUnitNumber());
var toHit = new AttackToHitData(attackingFormation.getSkill(), Internationalization.getText("acar.skill"));

processCriticalDamage(toHit, attackingFormation, attack);
processRange(toHit, attack);
processCombatUnit(toHit, unit);
// processCombatUnit(toHit, unit);
processTMM(toHit, game, attack);
processJUMP(toHit, game, attack);
processMorale(toHit, game, attack);
processSecondaryTarget(toHit, game, attack);
processCover(toHit, game, attack);
return toHit;
}

private static void processCover(AttackToHitData toHit, SimulationContext game, StandardUnitAttack attack) {
var target = game.getFormation(attack.getTargetId()).orElseThrow();
if (target.getMemory().getBoolean("cover").orElse(false)) {
toHit.addModifier(+1, Internationalization.getText("acar.cover"));
}
}

private static void processCriticalDamage(AttackToHitData toHit, Formation formation, StandardUnitAttack attack) {
SBFUnit combatUnit = formation.getUnits().get(attack.getUnitNumber());
if (combatUnit.getTargetingCrits() > 0) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
/*
* Copyright (c) 2025 - The MegaMek Team. All Rights Reserved.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
* Software Foundation; either version 2 of the License, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
package megamek.common.autoresolve.acar.action;

import megamek.common.Coords;
import megamek.common.autoresolve.acar.SimulationContext;
import megamek.common.autoresolve.acar.SimulationManager;
import megamek.common.autoresolve.acar.handler.MoveActionHandler;
import megamek.common.autoresolve.acar.handler.MoveToCoverActionHandler;

public class MoveToCoverAction implements Action {

private final int formationId;
private final int targetFormationId;
private final Coords destination;

public MoveToCoverAction(int formationId, int targetFormationId, Coords destination) {
this.formationId = formationId;
this.targetFormationId = targetFormationId;
this.destination = destination;
}

@Override
public int getEntityId() {
return formationId;
}

public int getTargetFormationId() {
return targetFormationId;
}

@Override
public MoveToCoverActionHandler getHandler(SimulationManager gameManager) {
return new MoveToCoverActionHandler(this, gameManager);
}

@Override
public boolean isDataValid(SimulationContext context) {
return context.getFormation(formationId).isPresent();
}

public Coords getDestination() {
return destination;
}

@Override
public String toString() {
return "[MoveAction]: ID: " + formationId;
}
}
64 changes: 64 additions & 0 deletions megamek/src/megamek/common/autoresolve/acar/board/Board1D.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
/*
* Copyright (c) 2025 - The MegaMek Team. All Rights Reserved.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
* Software Foundation; either version 2 of the License, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*
*/

package megamek.common.autoresolve.acar.board;

import megamek.common.Board;

public class Board1D {

private enum Type {
GROUND,
ATMOSPHERE,
SPACE
}

private enum TerrainType {
URBAN,
LIGHT_WOOD,
HEAVY_WOODS,
JUNGLE,
SHALLOW_WATER,
DEEP_WATER,
MARSH,
SWAMP,
LAVA,
THIN_ICE,
THICK_ICE,
DESERT,
SNOW,
ROUGH,
}

private final int size;

public Board1D(Board board) {
var c1 = board.getHeight() * board.getHeight();
var c2 = board.getWidth() * board.getWidth();
this.size = (int) Math.sqrt(c1 + c2);
}

public int getSize() {
return size;
}

public int getNorthMostPosition() {
return size-1;
}

public int getSouthMostPosition() {
return 0;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ public void execute() {
reporter.reportMovement(movingFormation);
}
}

movingFormation.getMemory().put("cover", false);
simulationManager().setFormationAt(movingFormation, boardLocation);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
/*
* Copyright (c) 2025 - The MegaMek Team. All Rights Reserved.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
* Software Foundation; either version 2 of the License, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
package megamek.common.autoresolve.acar.handler;

import megamek.common.BoardLocation;
import megamek.common.autoresolve.acar.SimulationManager;
import megamek.common.autoresolve.acar.action.MoveAction;
import megamek.common.autoresolve.acar.action.MoveToCoverAction;
import megamek.common.autoresolve.acar.report.MovementReport;

public class MoveToCoverActionHandler extends AbstractActionHandler {

private final MovementReport reporter;

public MoveToCoverActionHandler(MoveToCoverAction action, SimulationManager gameManager) {
super(action, gameManager);
this.reporter = new MovementReport(gameManager.getGame(), this::addReport);
}

@Override
public boolean cares() {
return game().getPhase().isMovement();
}

@Override
public void execute() {
MoveToCoverAction moveAction = (MoveToCoverAction) getAction();

var formationOpt = game().getFormation(moveAction.getEntityId());
var movingFormation = formationOpt.orElseThrow();
var x = movingFormation.getPosition().coords().getX();
var moveX = moveAction.getDestination().getX();

var targetFormationOpt = game().getFormation(moveAction.getTargetFormationId());
var boardLocation = game().clamp(new BoardLocation(moveAction.getDestination(), 0));

if (targetFormationOpt.isPresent()) {
var targetX = targetFormationOpt.get().getPosition().coords().getX();
var moveDir = x < moveX ? 1 : -1;
var targetDir = x < targetX ? 1 : -1;
var relativeDir = moveDir * targetDir;

reporter.reportMovement(movingFormation, targetFormationOpt.get(), relativeDir);
} else {
if (movingFormation.isWithdrawing()) {
reporter.reportRetreatMovement(movingFormation);
} else {
reporter.reportMovement(movingFormation);
}
}
movingFormation.getMemory().put("cover", true);
simulationManager().setFormationAt(movingFormation, boardLocation);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,10 @@ public boolean cares() {
return game().getPhase().isFiring();
}

private int getFormationId() {
return ((StandardUnitAttack) getAction()).getEntityId();
}

@Override
public void execute() {
var attack = (StandardUnitAttack) getAction();
Expand Down Expand Up @@ -134,7 +138,8 @@ private void applyDamage(Formation target, SBFUnit targetUnit, int[] damage, SBF
targetUnit.setCurrentArmor(Math.max(0, targetUnit.getCurrentArmor() - totalDamageApplied));

reporter.reportDamageDealt(targetUnit, totalDamageApplied, targetUnit.getCurrentArmor());

target.getMemory().put("lastAttackerId", getFormationId());
target.getMemory().put("wasDamagedAtRound", game().getCurrentRound());
if (targetUnit.getCurrentArmor() * 2 < totalDamageApplied) {
target.setHighStressEpisode();
reporter.reportStressEpisode();
Expand Down
Loading

0 comments on commit 041f818

Please sign in to comment.