/*
* AtBGameThread.java
*
* Derived from GameThread.java, Copyright (c) 2011.
*
* This file is part of MekHQ.
*
* MekHQ 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 3 of the License, or
* (at your option) any later version.
*
* MekHQ 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.
*
* You should have received a copy of the GNU General Public License
* along with MekHQ. If not, see <http://www.gnu.org/licenses/>.
*/
package mekhq;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.util.ArrayList;
import megamek.client.Client;
import megamek.client.bot.BotClient;
import megamek.client.bot.princess.Princess;
import megamek.client.ui.swing.ClientGUI;
import megamek.common.Entity;
import megamek.common.IGame;
import megamek.common.MapSettings;
import megamek.common.PlanetaryConditions;
import megamek.common.Player;
import megamek.common.UnitType;
import megamek.common.logging.LogLevel;
import mekhq.campaign.force.Lance;
import mekhq.campaign.mission.AtBScenario;
import mekhq.campaign.unit.Unit;
/**
* @author Neoancient
*
* Enhanced version of GameThread which imports settings and non-player
* units into the MM game
*
*/
public class AtBGameThread extends GameThread {
AtBScenario scenario;
public AtBGameThread(String name, Client c, MekHQ app, ArrayList<Unit> units, AtBScenario scenario) {
this(name, c, app, units, scenario, true);
}
public AtBGameThread(String name, Client c, MekHQ app, ArrayList<Unit> units, AtBScenario scenario, boolean started) {
super(name, c, app, units, started);
this.scenario = scenario;
}
@Override
public void run() {
client.addCloseClientListener(this);
if (swingGui != null) {
for (Client client2 : swingGui.getBots().values()) {
client2.die();
}
swingGui.getBots().clear();
}
createController();
swingGui = new ClientGUI(client, controller);
controller.clientgui = swingGui;
swingGui.initialize();
try {
client.connect();
} catch (Exception ex) {
MekHQ.logMessage("MegaMek client failed to connect to server");
MekHQ.logError(ex);
return;
}
try {
while (client.getLocalPlayer() == null) {
Thread.sleep(50);
}
// if game is running, shouldn't do the following, so detect the
// phase
for (int i = 0; (i < 1000) && (client.getGame().getPhase() == IGame.Phase.PHASE_UNKNOWN); i++) {
Thread.sleep(50);
System.out.println("Thread in unknown stage" );
}
if (((client.getGame() != null) && (client.getGame().getPhase() == IGame.Phase.PHASE_LOUNGE))) {
System.out.println("Thread in lounge" );
client.getLocalPlayer().setCamoCategory(app.getCampaign().getCamoCategory());
client.getLocalPlayer().setCamoFileName(app.getCampaign().getCamoFileName());
if (started) {
client.getGame().getOptions().loadOptions();
client.sendGameOptions("", app.getCampaign().getGameOptionsVector());
Thread.sleep(campaign.getCampaignOptions().getStartGameDelay());
}
MapSettings mapSettings = MapSettings.getInstance();
File mapgenFile = new File("data/mapgen/" + scenario.getMap() + ".xml");
try {
mapSettings = MapSettings.getInstance(new FileInputStream(mapgenFile));
} catch (FileNotFoundException ex) {
MekHQ.logError("Could not load map file data/mapgen/" + scenario.getMap() + ".xml");
MekHQ.logError(ex);
}
mapSettings.setBoardSize(scenario.getMapX(), scenario.getMapY());
mapSettings.setMapSize(1, 1);
mapSettings.getBoardsSelectedVector().clear();
mapSettings.getBoardsSelectedVector().add(MapSettings.BOARD_GENERATED);
client.sendMapSettings(mapSettings);
Thread.sleep(campaign.getCampaignOptions().getStartGameDelay());
PlanetaryConditions planetaryConditions = new PlanetaryConditions();
planetaryConditions.setLight(scenario.getLight());
planetaryConditions.setWeather(scenario.getWeather());
planetaryConditions.setWindStrength(scenario.getWind());
planetaryConditions.setFog(scenario.getFog());
planetaryConditions.setAtmosphere(scenario.getAtmosphere());
planetaryConditions.setGravity(scenario.getGravity());
client.sendPlanetaryConditions(planetaryConditions);
Thread.sleep(campaign.getCampaignOptions().getStartGameDelay());
client.getLocalPlayer().setStartingPos(scenario.getStart());
client.getLocalPlayer().setTeam(1);
/* If the player is making a combat drop (either required by scenario
* or player chose to deploy a DropShip), do not use deployment
* delay for slower scout units.
*/
boolean useDropship = false;
if (scenario.getLanceRole() == Lance.ROLE_SCOUT) {
for (Entity en : scenario.getAlliesPlayer()) {
if (UnitType.determineUnitTypeCode(en) == UnitType.DROPSHIP) {
useDropship = true;
break;
}
}
if (!useDropship) {
for (Unit unit : units) {
if (UnitType.determineUnitTypeCode(unit.getEntity()) == UnitType.DROPSHIP) {
useDropship = true;
break;
}
}
}
}
for (Unit unit : units) {
// Get the Entity
Entity entity = unit.getEntity();
// Set the TempID for autoreporting
entity.setExternalIdAsString(unit.getId().toString());
// Set the owner
entity.setOwner(client.getLocalPlayer());
// Calculate deployment round
int speed = entity.getWalkMP();
if (entity.getJumpMP() > 0) {
if (entity instanceof megamek.common.Infantry) {
speed = entity.getJumpMP();
} else {
speed++;
}
}
/* Set scenario type-specific delay */
int deploymentRound = Math.max(entity.getDeployRound(), scenario.getDeploymentDelay() - speed);
/* Lances deployed in scout roles always deploy units in 6-walking speed turns */
if (scenario.getLanceRole() == Lance.ROLE_SCOUT
&& scenario.getLance(campaign).getForceId() == scenario.getLanceForceId()
&& !useDropship) {
deploymentRound = Math.max(deploymentRound, 6 - speed);
}
entity.setDeployRound(Math.max(0, deploymentRound));
// Add Mek to game
client.sendAddEntity(entity);
// Wait a few secs to not overuse bandwith
Thread.sleep(campaign.getCampaignOptions().getStartGameDelay());
}
/* Add player-controlled ally units */
for (Entity entity : scenario.getAlliesPlayer()) {
if (null == entity) {
continue;
}
entity.setOwner(client.getLocalPlayer());
int speed = entity.getWalkMP();
if (entity.getJumpMP() > 0) {
if (entity instanceof megamek.common.Infantry) {
speed = entity.getJumpMP();
} else {
speed++;
}
}
int deploymentRound = Math.max(entity.getDeployRound(), scenario.getDeploymentDelay() - speed);
if (scenario.getLanceRole() == Lance.ROLE_SCOUT
&& scenario.getLance(campaign).getForceId() == scenario.getLanceForceId()
&& !useDropship) {
deploymentRound = Math.max(deploymentRound, 6 - speed);
}
entity.setDeployRound(Math.max(0, deploymentRound));
client.sendAddEntity(entity);
Thread.sleep(campaign.getCampaignOptions().getStartGameDelay());
}
client.sendPlayerInfo();
/* Add bots */
for (int i = 0; i < scenario.getNumBots(); i++) {
AtBScenario.BotForce bf = scenario.getBotForce(i);
String name = bf.getName();
if (swingGui.getBots().containsKey(name)) {
int append = 2;
while (swingGui.getBots().containsKey(name + append)) {
append++;
}
name += append;
}
Princess botClient = new Princess(name, client.getHost(), client.getPort(), LogLevel.ERROR);
botClient.setBehaviorSettings(bf.getBehaviorSettings());
try {
botClient.connect();
} catch (Exception e) {
MekHQ.logError("Could not connect with Bot name " + bf.getName());
}
swingGui.getBots().put(name, botClient);
configureBot(botClient, bf);
}
}
while(!stop) {
Thread.sleep(50);
}
} catch (Exception e) {
MekHQ.logError(e);
}
finally {
client.die();
client = null;
swingGui = null;
controller = null;
}
}
/**
* wait for the server to add the bot client, then send starting position,
* camo, and entities
*
* @param botClient
* @param botForce
*/
private void configureBot(BotClient botClient, AtBScenario.BotForce botForce) {
try {
/* Wait for the server to add the bot client, but allow a timeout
* rather than blocking
*/
int retries = 50;
while (retries-- > 0 && null == botClient.getLocalPlayer()) {
sleep(50);
}
if (null == botClient.getLocalPlayer()) {
MekHQ.logError("Could not configure bot " + botClient.getName());
} else {
for (Entity entity : botForce.getEntityList()) {
if (null == entity) {
continue;
}
entity.setOwner(botClient.getLocalPlayer());
botClient.sendAddEntity(entity);
Thread.sleep(campaign.getCampaignOptions().getStartGameDelay());
}
botClient.getLocalPlayer().setTeam(botForce.getTeam());
botClient.getLocalPlayer().setStartingPos(botForce.getStart());
if (botForce.getCamoCategory() == Player.NO_CAMO) {
if (botForce.getColorIndex() >= 0) {
botClient.getLocalPlayer().setColorIndex(botForce.getColorIndex());
}
} else {
botClient.getLocalPlayer().setCamoCategory(botForce.getCamoCategory());
botClient.getLocalPlayer().setCamoFileName(botForce.getCamoFileName());
}
botClient.sendPlayerInfo();
}
} catch (Exception e) {
MekHQ.logError(e);
}
}
}